@lowdefy/server-dev 6.1.0 → 7.1.0
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/client/App.jsx +52 -24
- package/client/Inspector.jsx +73 -30
- package/client/JourneyObserver.jsx +47 -0
- package/client/Page.jsx +54 -22
- package/client/Recorder.jsx +73 -0
- package/client/Routing.jsx +37 -13
- package/client/clientBuildImports.test.mjs +2 -0
- package/client/devStreamConnections.test.mjs +40 -0
- package/client/feedback/FeedbackMount.jsx +2 -2
- package/client/feedback/FeedbackOverlay.jsx +7 -4
- package/client/feedback/feedbackStyles.js +3 -0
- package/client/journeyObserver/startJourneyObserver.js +101 -0
- package/client/journeyObserver/startJourneyObserver.test.mjs +149 -0
- package/client/openInEditor/OpenInEditorListener.jsx +2 -0
- package/client/recorder/buildEngineRecord.js +37 -0
- package/client/recorder/buildInteractionRecord.js +64 -0
- package/client/recorder/buildTraceEvent.js +57 -0
- package/client/recorder/buildTraceEvent.test.mjs +81 -0
- package/client/recorder/chunkRecords.js +69 -0
- package/client/recorder/chunkRecords.test.mjs +59 -0
- package/client/recorder/collectEventActions.js +30 -0
- package/client/recorder/collectEventEndpoints.js +40 -0
- package/client/recorder/collectEventRequests.js +39 -0
- package/client/recorder/createPairingBuffer.js +187 -0
- package/client/recorder/createPairingBuffer.test.mjs +405 -0
- package/client/recorder/createPasswordRedactor.js +84 -0
- package/client/recorder/createRecordBatcher.js +54 -0
- package/client/recorder/createRecordBatcher.test.mjs +76 -0
- package/client/recorder/createRecorder.js +216 -0
- package/client/recorder/createRecorder.test.mjs +318 -0
- package/client/recorder/createRecordingSession.js +61 -0
- package/client/recorder/createRecordingSession.test.mjs +72 -0
- package/client/recorder/diffStateWrites.js +77 -0
- package/client/recorder/diffStateWrites.test.mjs +66 -0
- package/client/recorder/isEventCall.js +30 -0
- package/client/recorder/jsonType.js +39 -0
- package/client/recorder/keyChord.js +47 -0
- package/client/recorder/keyChord.test.mjs +50 -0
- package/client/recorder/sendRecords.js +40 -0
- package/client/recorder/toJsonSafe.js +29 -0
- package/lib/client/BuildingPage.jsx +3 -1
- package/lib/client/ErrorBar.jsx +17 -13
- package/lib/client/RedirectingPage.jsx +56 -0
- package/lib/client/auth/Auth.jsx +11 -6
- package/lib/client/auth/AuthConfigured.jsx +222 -36
- package/lib/client/auth/AuthNotConfigured.js +45 -4
- package/lib/client/auth/authNotConfiguredParity.test.mjs +61 -0
- package/lib/client/auth/authTemplateSync.test.mjs +40 -0
- package/lib/client/auth/betterAuthSessionContract.test.mjs +181 -0
- package/lib/client/auth/createFetchCheckingBuild.js +45 -0
- package/lib/client/bundleBuildId.js +25 -0
- package/lib/client/collectVisibleBlockIds.js +51 -0
- package/lib/client/getCspNonce.js +25 -0
- package/lib/client/getPagePath.js +36 -0
- package/lib/client/getPagePath.test.mjs +51 -0
- package/lib/client/utils/formatErrorsForCopy.js +30 -0
- package/lib/client/utils/formatErrorsForCopy.test.mjs +39 -0
- package/lib/client/utils/getErrorBarColor.js +25 -0
- package/lib/client/utils/getErrorBarColor.test.mjs +34 -0
- package/lib/client/utils/request.js +8 -1
- package/lib/client/utils/usePageConfig.js +89 -25
- package/lib/client/utils/usePageConfig.test.mjs +198 -13
- package/lib/configTree/buildConfigTree.mjs +58 -0
- package/lib/configTree/buildConfigTree.test.mjs +77 -0
- package/lib/configTree/collectConfigText.mjs +101 -0
- package/lib/configTree/collectConfigText.test.mjs +116 -0
- package/lib/configTree/prepareScratchServer.mjs +46 -0
- package/lib/configTree/runConfigTreeBuild.mjs +88 -0
- package/lib/configTree/runConfigTreeBuild.skipPluginChecks.test.mjs +74 -0
- package/lib/configTree/runConfigTreeBuild.test.mjs +202 -0
- package/lib/docs/JourneyStepError.js +30 -0
- package/lib/docs/acquireBrowserSlot.js +30 -0
- package/lib/docs/addNestedEndpoints.js +54 -0
- package/lib/docs/addNestedEndpoints.test.mjs +185 -0
- package/lib/docs/addWriteFlags.js +77 -0
- package/lib/docs/buildEditedPages.js +50 -0
- package/lib/docs/buildWaitHeader.js +21 -0
- package/lib/docs/captureAnnotatedScreenshot.js +23 -12
- package/lib/docs/checkAgentFiles.js +148 -0
- package/lib/docs/checkAgentFiles.test.mjs +225 -0
- package/lib/docs/checkStepReferences.js +239 -0
- package/lib/docs/checkStepReferences.test.mjs +173 -0
- package/lib/docs/checkpointStore.js +3 -0
- package/lib/docs/clientErrorStore.js +18 -1
- package/lib/docs/clientErrorStore.test.mjs +46 -0
- package/lib/docs/collectExercised.js +52 -0
- package/lib/docs/createBrowserLifecycle.js +102 -0
- package/lib/docs/createBrowserLifecycle.test.mjs +212 -0
- package/lib/docs/createDocsMcpServer.js +345 -388
- package/lib/docs/createDocsMcpServer.test.mjs +644 -4
- package/lib/docs/createDocsMcpServerRunJourney.test.mjs +148 -0
- package/lib/docs/createJourneyActors.chromium.test.mjs +227 -0
- package/lib/docs/createJourneyActors.js +213 -0
- package/lib/docs/createJourneyActors.test.mjs +79 -0
- package/lib/docs/createJourneyObservations.js +80 -0
- package/lib/docs/createLeftOriginError.js +26 -0
- package/lib/docs/createNetworkCounter.js +101 -0
- package/lib/docs/dataSets/checkSharedCollectionIds.js +78 -0
- package/lib/docs/dataSets/dataSessionRegistry.js +25 -0
- package/lib/docs/dataSets/dataSetJourneys.chromium.mongodb.test.mjs +727 -0
- package/lib/docs/dataSets/describeDataSetResult.js +25 -0
- package/lib/docs/dataSets/describeDatabaseTarget.js +46 -0
- package/lib/docs/dataSets/describeTargetKey.js +29 -0
- package/lib/docs/dataSets/deserializeFixture.js +34 -0
- package/lib/docs/dataSets/drainSessionWork.js +37 -0
- package/lib/docs/dataSets/drainSessionWork.test.mjs +64 -0
- package/lib/docs/dataSets/duplicateIndexName.js +24 -0
- package/lib/docs/dataSets/getDataStore.js +106 -0
- package/lib/docs/dataSets/getDataStore.mongodb.test.mjs +63 -0
- package/lib/docs/dataSets/getDataStore.test.mjs +195 -0
- package/lib/docs/dataSets/groupDataSetByCollection.js +52 -0
- package/lib/docs/dataSets/insertFixture.js +57 -0
- package/lib/docs/dataSets/insertGeneratedDocuments.js +41 -0
- package/lib/docs/dataSets/isDataStoreGone.js +29 -0
- package/lib/docs/dataSets/loadDataSetCollection.js +42 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.js +52 -0
- package/lib/docs/dataSets/mergeCollectionIndexes.test.mjs +59 -0
- package/lib/docs/dataSets/openDataSession.js +133 -0
- package/lib/docs/dataSets/openDataSession.mongodb.test.mjs +493 -0
- package/lib/docs/dataSets/pickDataStorePort.js +58 -0
- package/lib/docs/dataSets/pickDataStorePort.test.mjs +63 -0
- package/lib/docs/dataSets/readConnectionArtifacts.js +46 -0
- package/lib/docs/dataSets/readDataSession.js +41 -0
- package/lib/docs/dataSets/readDataSession.test.mjs +57 -0
- package/lib/docs/dataSets/readDataSet.js +83 -0
- package/lib/docs/dataSets/readDataSet.test.mjs +251 -0
- package/lib/docs/dataSets/registerDataStoreShutdown.js +47 -0
- package/lib/docs/dataSets/removeDataStoreFiles.js +32 -0
- package/lib/docs/dataSets/resolveDataSetCollection.js +46 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.js +106 -0
- package/lib/docs/dataSets/resolveJourneyDataSet.test.mjs +130 -0
- package/lib/docs/dataSets/sessionDatabaseName.js +32 -0
- package/lib/docs/dataSets/sweepOrphanDatabases.js +36 -0
- package/lib/docs/dataSets/test/app/lowdefy.yaml +225 -0
- package/lib/docs/dataSets/test/app/modules/archive/module.lowdefy.yaml +30 -0
- package/lib/docs/dataSets/test/app/tests/data/shop.yaml +12 -0
- package/lib/docs/dataSets/test/buildTestApp.mjs +43 -0
- package/lib/docs/devEventBus.js +136 -0
- package/lib/docs/devEventBus.test.mjs +269 -0
- package/lib/docs/devToolDefinitions.js +529 -0
- package/lib/docs/docSources.js +21 -0
- package/lib/docs/docs.test.mjs +171 -15
- package/lib/docs/docsIndex.test.mjs +377 -0
- package/lib/docs/evalOperator.js +5 -3
- package/lib/docs/evalOperatorHeadless.js +84 -12
- package/lib/docs/evalOperatorHeadless.test.mjs +7 -1
- package/lib/docs/evalOperatorInTab.js +2 -1
- package/lib/docs/findConfig.js +95 -49
- package/lib/docs/fitResponse.js +81 -0
- package/lib/docs/fitResponse.test.mjs +128 -0
- package/lib/docs/formatFeedback.js +26 -5
- package/lib/docs/formatFeedback.test.mjs +48 -0
- package/lib/docs/getAppMap.js +7 -1
- package/lib/docs/getBrowser.js +150 -80
- package/lib/docs/getBrowser.test.mjs +407 -16
- package/lib/docs/getBuildId.js +61 -0
- package/lib/docs/getBuildId.test.mjs +84 -0
- package/lib/docs/getBuildStatus.js +81 -7
- package/lib/docs/getBuildStatus.test.mjs +229 -0
- package/lib/docs/getBuildStatusAfterEdits.js +35 -0
- package/lib/docs/getBuildStatusAfterEdits.test.mjs +76 -0
- package/lib/docs/getCoreDoc.js +9 -1
- package/lib/docs/getDoc.js +100 -0
- package/lib/docs/getDocsIndex.js +152 -0
- package/lib/docs/getHazards.js +115 -0
- package/lib/docs/getHazards.test.mjs +175 -0
- package/lib/docs/getMailOutboxDirectory.js +26 -0
- package/lib/docs/getOverview.js +79 -13
- package/lib/docs/getOverviewBasePath.test.mjs +37 -0
- package/lib/docs/getPageBuildStatus.js +46 -0
- package/lib/docs/getPluginDoc.js +21 -23
- package/lib/docs/getSchema.js +33 -1
- package/lib/docs/getStaleStatus.js +36 -0
- package/lib/docs/getStaleStatus.test.mjs +74 -0
- package/lib/docs/guardJourneyOrigin.js +39 -0
- package/lib/docs/inspectState.js +5 -3
- package/lib/docs/inspectStateFromTab.js +2 -2
- package/lib/docs/inspectStateHeadless.js +89 -27
- package/lib/docs/inspectStateHeadless.test.mjs +20 -1
- package/lib/docs/installHeadlessShell.failure.test.mjs +45 -0
- package/lib/docs/installHeadlessShell.js +123 -0
- package/lib/docs/installHeadlessShell.test.mjs +70 -0
- package/lib/docs/installHeadlessShell.timeout.test.mjs +72 -0
- package/lib/docs/isHeadlessShellIncomplete.js +34 -0
- package/lib/docs/isHeadlessShellIncomplete.test.mjs +63 -0
- package/lib/docs/isPageReady.js +77 -0
- package/lib/docs/isPageReady.test.mjs +235 -0
- package/lib/docs/isRunErrorEntry.js +25 -0
- package/lib/docs/journeyMutantCookie.chromium.test.mjs +150 -0
- package/lib/docs/journeyRunRecording.js +35 -0
- package/lib/docs/journeyRunRecording.test.mjs +39 -0
- package/lib/docs/keepEventStreamAlive.js +68 -0
- package/lib/docs/keepEventStreamAlive.test.mjs +77 -0
- package/lib/docs/launchBrowser.js +83 -0
- package/lib/docs/launchBrowser.test.mjs +175 -0
- package/lib/docs/listModuleDocEntries.js +69 -0
- package/lib/docs/listPackageDocFiles.js +67 -0
- package/lib/docs/listPluginDocEntries.js +111 -0
- package/lib/docs/listPlugins.js +9 -58
- package/lib/docs/listTypes.js +14 -6
- package/lib/docs/loadFrameworkHazards.js +40 -0
- package/lib/docs/loadFrameworkHazards.test.mjs +43 -0
- package/lib/docs/loadState.js +103 -35
- package/lib/docs/makeModuleManifestDoc.js +174 -0
- package/lib/docs/matchExercisedPages.js +35 -0
- package/lib/docs/matchJourneyRoute.js +69 -0
- package/lib/docs/matchJourneyRoute.test.mjs +178 -0
- package/lib/docs/mergeNetworkSnapshots.js +49 -0
- package/lib/docs/nextJourneySequence.js +30 -0
- package/lib/docs/noBrowserError.js +22 -0
- package/lib/docs/observe/TRANSIENT_SELECTOR.js +21 -0
- package/lib/docs/observe/claimExpectedErrors.js +67 -0
- package/lib/docs/observe/createJourneyAppErrors.js +236 -0
- package/lib/docs/observe/createJourneyAppErrors.test.mjs +385 -0
- package/lib/docs/observe/evaluateInvariants.js +183 -0
- package/lib/docs/observe/evaluateInvariants.test.mjs +299 -0
- package/lib/docs/observe/findingKey.js +29 -0
- package/lib/docs/observe/hasNoEffect.js +31 -0
- package/lib/docs/observe/hasNoEffect.test.mjs +37 -0
- package/lib/docs/observe/installStepObserver.js +72 -0
- package/lib/docs/observe/isAppApiUrl.js +33 -0
- package/lib/docs/observe/parseAppApiUrl.js +37 -0
- package/lib/docs/observe/readStepObserver.js +42 -0
- package/lib/docs/observe/relativeSource.js +29 -0
- package/lib/docs/observe/resolveConfigKeySource.js +33 -0
- package/lib/docs/observe/takeJourneyEvents.js +36 -0
- package/lib/docs/observe/toAppErrorFailure.js +61 -0
- package/lib/docs/observe/usesSearchStage.js +45 -0
- package/lib/docs/observe/waitForClientErrorReports.js +31 -0
- package/lib/docs/observe/watchJourneyContext.js +75 -0
- package/lib/docs/observe/withAppErrors.js +31 -0
- package/lib/docs/observe/withAppErrors.test.mjs +101 -0
- package/lib/docs/openJourney.js +94 -0
- package/lib/docs/openJourneyEmail.js +41 -0
- package/lib/docs/openJourneyEmail.test.mjs +187 -0
- package/lib/docs/pageBlocks.js +47 -0
- package/lib/docs/pageBuildStatus.test.mjs +103 -0
- package/lib/{client/setPageId.js → docs/parseModuleSource.js} +11 -12
- package/lib/docs/rails/authEngineActions.js +53 -0
- package/lib/docs/rails/authEngineActions.test.mjs +69 -0
- package/lib/docs/rails/authEngineMethods.js +52 -0
- package/lib/docs/rails/authEngineMethods.test.mjs +36 -0
- package/lib/docs/rails/checkAuthActionsRan.js +66 -0
- package/lib/docs/rails/checkAuthActionsRan.test.mjs +149 -0
- package/lib/docs/rails/checkClickRails.js +56 -0
- package/lib/docs/rails/createDataSetRails.js +82 -0
- package/lib/docs/rails/createDataSetRails.test.mjs +172 -0
- package/lib/docs/rails/findExternalBlocks.js +147 -0
- package/lib/docs/rails/findExternalBlocks.test.mjs +254 -0
- package/lib/docs/rails/installAuthActionRecorder.js +56 -0
- package/lib/docs/rails/readAuthActionRecorder.js +32 -0
- package/lib/docs/rails/readBuiltArtifact.js +30 -0
- package/lib/docs/readConnectionPlugins.js +26 -0
- package/lib/docs/readDevAuthMode.js +32 -0
- package/lib/docs/readDocEntry.js +40 -0
- package/lib/docs/readDocTitle.js +26 -0
- package/lib/docs/readJourneyEmailMatch.js +57 -0
- package/lib/docs/readJourneyEmailMatch.test.mjs +110 -0
- package/lib/docs/readJourneySession.js +56 -0
- package/lib/docs/readMailOutbox.js +37 -0
- package/lib/docs/readPagePath.js +27 -0
- package/lib/docs/readPluginPackages.js +99 -0
- package/lib/docs/readProxyBuildWait.js +38 -0
- package/lib/docs/readRoutineSteps.js +45 -0
- package/lib/docs/registerShownTextEngine.js +118 -0
- package/lib/docs/requestRestart.js +30 -0
- package/lib/docs/requestRestart.test.mjs +49 -0
- package/lib/docs/resolvePageInstance.js +46 -0
- package/lib/docs/resolvePageInstance.test.mjs +81 -0
- package/lib/docs/resolveSource.js +11 -7
- package/lib/docs/resolveSource.test.mjs +1 -1
- package/lib/docs/resolveToolCaller.js +62 -0
- package/lib/docs/reviewPage.js +51 -0
- package/lib/docs/reviewPageBuilds.js +56 -0
- package/lib/docs/reviewPageBuilds.test.mjs +207 -0
- package/lib/docs/runCheck.js +75 -0
- package/lib/docs/runCheck.test.mjs +91 -0
- package/lib/docs/runCheckChild.js +49 -0
- package/lib/docs/runEndpoint.js +185 -0
- package/lib/docs/runEndpoint.test.mjs +509 -0
- package/lib/docs/runErrorBuffers.js +99 -0
- package/lib/docs/runErrorBuffers.test.mjs +95 -0
- package/lib/docs/runJourney.js +347 -0
- package/lib/docs/runJourney.test.mjs +2383 -0
- package/lib/docs/runJourneyAsUsers.js +44 -0
- package/lib/docs/runJourneyDataSet.test.mjs +274 -0
- package/lib/docs/runJourneySteps.js +1320 -0
- package/lib/docs/runRequest.js +100 -59
- package/lib/docs/runRequest.test.mjs +190 -0
- package/lib/docs/saveAnnotatedScreenshot.js +1 -1
- package/lib/docs/scaffoldPage.js +3 -1
- package/lib/docs/screenshotPage.js +163 -11
- package/lib/docs/screenshotPage.test.mjs +263 -1
- package/lib/docs/screenshotPageClip.test.mjs +4 -0
- package/lib/docs/searchDocs.js +82 -30
- package/lib/docs/searchDocs.test.mjs +100 -0
- package/lib/docs/searchIcons.js +90 -0
- package/lib/docs/searchIcons.test.mjs +127 -0
- package/lib/docs/selectExercised.js +39 -0
- package/lib/docs/selectFinalState.js +66 -0
- package/lib/docs/selectFinalState.test.mjs +51 -0
- package/lib/docs/serverErrorStore.js +54 -0
- package/lib/docs/serverErrorStore.test.mjs +50 -0
- package/lib/docs/setupTestFixtures.mjs +133 -39
- package/lib/docs/shownTextSelector.js +28 -0
- package/lib/docs/snapshotState.js +13 -5
- package/lib/docs/splitSearchTerms.js +62 -0
- package/lib/docs/splitSearchTerms.test.mjs +50 -0
- package/lib/docs/stateCheckpoints.test.mjs +77 -0
- package/lib/docs/tabAvailable.js +6 -5
- package/lib/docs/tabChannel.js +127 -21
- package/lib/docs/tabChannel.test.mjs +187 -29
- package/lib/docs/unsettledPageNote.js +24 -0
- package/lib/docs/validateJourneyMail.js +36 -0
- package/lib/docs/validateJourneyTimeout.js +38 -0
- package/lib/docs/validateJourneyTimeout.test.mjs +29 -0
- package/lib/docs/validateRecordingParam.js +42 -0
- package/lib/docs/validateStateSelection.js +33 -0
- package/lib/docs/validateStateSelection.test.mjs +33 -0
- package/lib/docs/validateViewport.js +51 -0
- package/lib/docs/validateViewport.test.mjs +54 -0
- package/lib/docs/waitForBuild.js +50 -0
- package/lib/docs/waitForBuild.test.mjs +75 -0
- package/lib/docs/waitForJourneyEmail.js +77 -0
- package/lib/docs/withBrowserSlot.js +45 -0
- package/lib/docs/withBrowserSlot.test.mjs +75 -0
- package/lib/docs/withDataSession.js +53 -0
- package/lib/server/applyDataSetRedirect.js +92 -0
- package/lib/server/applyDataSetRedirect.test.mjs +446 -0
- package/lib/server/applyDataSetRedirectTenantReach.test.mjs +207 -0
- package/lib/server/applyDataSetRedirectWalled.test.mjs +134 -0
- package/lib/server/auth/createSystemContext.js +73 -0
- package/lib/server/auth/{getAuthConfig.js → getAuth.js} +15 -9
- package/lib/server/auth/getHeadlessUser.js +9 -8
- package/lib/server/auth/getHeadlessUser.test.mjs +41 -0
- package/lib/server/auth/getMockUser.js +18 -14
- package/lib/server/auth/{session.js → getStrategies.js} +17 -16
- package/lib/server/auth/headlessUser.js +3 -2
- package/lib/server/auth/journeyActor.js +35 -0
- package/lib/server/auth/resolveHeadlessUser.test.mjs +0 -4
- package/lib/server/checkPageRecord.js +44 -0
- package/lib/server/contextMapBudget.js +24 -0
- package/lib/server/contextMapBudget.test.mjs +98 -0
- package/lib/server/continueJitKeys.js +28 -0
- package/lib/server/continueJitKeys.test.mjs +43 -0
- package/lib/server/createDataSessionEndedError.js +33 -0
- package/lib/server/createDataSetRefusal.js +26 -0
- package/lib/server/createLowdefyContext.js +168 -41
- package/lib/server/createLowdefyContext.test.mjs +331 -8
- package/lib/server/getClientAddress.js +51 -0
- package/lib/server/getClientAddress.test.mjs +56 -0
- package/lib/server/getPageJitEnrichment.test.mjs +29 -11
- package/lib/server/hashConfigContent.js +26 -0
- package/lib/server/importAppCode.test.mjs +57 -0
- package/lib/server/isRoutineStep.js +27 -0
- package/lib/server/jitPageBuilder.js +309 -126
- package/lib/server/jitPageBuilder.skipPluginChecks.test.mjs +78 -0
- package/lib/server/jitPageBuilder.test.mjs +218 -0
- package/lib/server/journeyCookies/JOURNEY_COOKIES.js +37 -0
- package/lib/server/journeyCookies/forwardJourneyCookies.js +46 -0
- package/lib/server/journeyCookies/readJourneyCookie.js +52 -0
- package/lib/server/journeyCookies/writeJourneyCookie.js +46 -0
- package/lib/server/journeyCookies.js +22 -0
- package/lib/server/journeyCookies.test.mjs +145 -0
- package/lib/server/loadDynamicJsMap.js +47 -0
- package/lib/server/log/createHandleError.js +38 -2
- package/lib/server/log/createHandleError.test.mjs +125 -2
- package/lib/server/log/createLogger.js +3 -0
- package/lib/server/log/createLogger.test.mjs +15 -0
- package/lib/server/log/logRequest.js +2 -3
- package/lib/server/mutantDataSetWrappers.test.mjs +115 -0
- package/lib/server/mutants/applyMutant.js +39 -0
- package/lib/server/mutants/artifactPatterns.js +25 -0
- package/lib/server/mutants/buildAnchor.js +45 -0
- package/lib/server/mutants/collectSharedIds.js +41 -0
- package/lib/server/mutants/configPathSegments.js +38 -0
- package/lib/server/mutants/createMutantReadConfigFile.js +42 -0
- package/lib/server/mutants/describeEvent.js +22 -0
- package/lib/server/mutants/enumerateArtifact.js +56 -0
- package/lib/server/mutants/findNodeByKey.js +45 -0
- package/lib/server/mutants/findNodeByPointer.js +49 -0
- package/lib/server/mutants/getArtifactKind.js +32 -0
- package/lib/server/mutants/groupMutantCopies.js +56 -0
- package/lib/server/mutants/hashArtifact.js +25 -0
- package/lib/server/mutants/hashMutantTarget.js +34 -0
- package/lib/server/mutants/listMutants.js +122 -0
- package/lib/server/mutants/listMutants.test.mjs +502 -0
- package/lib/server/mutants/mutantId.js +30 -0
- package/lib/server/mutants/mutantRuns.js +57 -0
- package/lib/server/mutants/mutantRuns.test.mjs +136 -0
- package/lib/server/mutants/operators/dropAction.js +47 -0
- package/lib/server/mutants/operators/dropBlock.js +44 -0
- package/lib/server/mutants/operators/dropPayload.js +52 -0
- package/lib/server/mutants/operators/dropStep.js +44 -0
- package/lib/server/mutants/operators/flipVisible.js +53 -0
- package/lib/server/mutants/operators/index.js +37 -0
- package/lib/server/mutants/operators/retargetLink.js +72 -0
- package/lib/server/mutants/operators/skipValidate.js +77 -0
- package/lib/server/mutants/operators/swapIf.js +112 -0
- package/lib/server/mutants/operators.test.mjs +396 -0
- package/lib/server/mutants/positionFreePath.js +38 -0
- package/lib/server/mutants/removeFromParent.js +28 -0
- package/lib/server/mutants/test/fixtures.mjs +173 -0
- package/lib/server/mutants/test/keyArtifact.mjs +63 -0
- package/lib/server/mutants/validateMutantParam.js +69 -0
- package/lib/server/mutants/validateMutantsBody.js +88 -0
- package/lib/server/mutants/walkArtifact.js +179 -0
- package/lib/server/pageBuildRecords.js +131 -0
- package/lib/server/pageBuildRecords.test.mjs +258 -0
- package/lib/server/pageCache.mjs +22 -7
- package/lib/server/pageCache.test.mjs +22 -7
- package/lib/server/pageRebuilds.test.mjs +543 -0
- package/lib/server/pruneJitMaps.js +36 -0
- package/lib/server/pruneJitMaps.test.mjs +55 -0
- package/lib/server/readInstanceRecord.js +33 -0
- package/lib/server/readInstanceRecord.test.mjs +99 -0
- package/lib/server/readMergedMaps.js +86 -0
- package/lib/server/readMergedMaps.test.mjs +79 -0
- package/lib/server/recording/appendRecords.js +33 -0
- package/lib/server/recording/errorRecordingStamp.js +34 -0
- package/lib/server/recording/errorRecordingStamp.test.mjs +31 -0
- package/lib/server/recording/isRecordingEnabled.js +31 -0
- package/lib/server/recording/readRecordingCookie.js +71 -0
- package/lib/server/recording/readRecordingCookie.test.mjs +73 -0
- package/lib/server/recording/recordingCookiePayload.js +33 -0
- package/lib/server/recording/servedBuilds.js +46 -0
- package/lib/server/recording/servedBuilds.test.mjs +42 -0
- package/lib/server/sinkExternalConnections.js +95 -0
- package/lib/server/sinkExternalConnections.test.mjs +135 -0
- package/lib/server/skipStaleMapWrites.js +62 -0
- package/lib/server/skipStaleMapWrites.test.mjs +113 -0
- package/lib/server/startIdleGc.js +67 -0
- package/lib/server/startIdleGc.test.mjs +138 -0
- package/lib/server/testFixtures/importAppCodeTwice.mjs +70 -0
- package/lib/server/trackSessionWork.js +30 -0
- package/lib/vite/createDevServerExclude.js +40 -0
- package/lib/vite/createDevServerExclude.test.mjs +79 -0
- package/manager/getContext.mjs +25 -3
- package/manager/processes/initialBuild.mjs +17 -1
- package/manager/processes/initialBuild.test.mjs +104 -0
- package/manager/processes/lowdefyBuild.mjs +31 -7
- package/manager/processes/lowdefyBuild.skipPluginChecks.test.mjs +72 -0
- package/manager/processes/lowdefyBuild.test.mjs +136 -1
- package/manager/processes/optimizeDependencies.mjs +59 -0
- package/manager/processes/restartServer.mjs +34 -6
- package/manager/processes/restartServer.test.mjs +162 -0
- package/manager/processes/shutdownServer.mjs +11 -0
- package/manager/processes/shutdownServer.test.mjs +45 -0
- package/manager/processes/startFirstServer.mjs +46 -0
- package/manager/processes/startFirstServer.test.mjs +326 -0
- package/manager/processes/startMailSink.mjs +135 -0
- package/manager/processes/startMailSink.test.mjs +146 -0
- package/manager/processes/startProxy.mjs +129 -12
- package/manager/processes/startProxy.test.mjs +366 -0
- package/manager/processes/startServer.mjs +47 -6
- package/manager/processes/startServer.test.mjs +155 -0
- package/manager/processes/startWatchers.mjs +6 -4
- package/manager/processes/syncServer.mjs +69 -0
- package/manager/processes/syncServer.test.mjs +141 -0
- package/manager/processes/waitForDevServer.mjs +48 -0
- package/manager/processes/waitForDevServer.test.mjs +112 -0
- package/manager/run.mjs +128 -43
- package/manager/utils/BatchChanges.mjs +21 -5
- package/manager/utils/BatchChanges.test.mjs +77 -0
- package/manager/utils/acquireDevInstance.mjs +99 -0
- package/manager/utils/acquireDevInstance.test.mjs +160 -0
- package/manager/utils/createBuildActivity.mjs +67 -0
- package/manager/utils/createBuildActivity.test.mjs +58 -0
- package/manager/utils/createChangeSignal.mjs +39 -0
- package/manager/utils/createChangeSignal.test.mjs +62 -0
- package/manager/utils/createCustomPluginMessagesMap.mjs +23 -33
- package/manager/utils/createCustomPluginTypesMap.mjs +24 -30
- package/manager/utils/createCustomPluginTypesMap.test.mjs +94 -0
- package/manager/utils/createDotPathIgnore.mjs +44 -0
- package/manager/utils/createDotPathIgnore.test.mjs +65 -0
- package/manager/utils/createIdleGc.mjs +51 -0
- package/manager/utils/createIdleGc.test.mjs +77 -0
- package/manager/utils/createRequestActivity.mjs +100 -0
- package/manager/utils/createRequestActivity.test.mjs +121 -0
- package/manager/utils/createServerArtifactTracker.mjs +83 -0
- package/manager/utils/createServerArtifactTracker.test.mjs +78 -0
- package/manager/utils/createServerEnv.mjs +39 -0
- package/manager/utils/filesHaveSameBytes.mjs +41 -0
- package/manager/utils/findBuildFilesOutsideWatch.mjs +59 -0
- package/manager/utils/findBuildFilesOutsideWatch.test.mjs +111 -0
- package/manager/utils/importFresh.mjs +46 -0
- package/manager/utils/importFresh.test.mjs +72 -0
- package/manager/utils/importFreshWorker.mjs +20 -0
- package/manager/utils/killTaggedBrowser.mjs +35 -0
- package/manager/utils/pagePathChanged.mjs +56 -0
- package/manager/utils/pruneRecordings.mjs +85 -0
- package/manager/utils/pruneRecordings.test.mjs +117 -0
- package/manager/utils/publishBuildDirectory.mjs +121 -0
- package/manager/utils/publishBuildDirectory.order.test.mjs +74 -0
- package/manager/utils/publishBuildDirectory.test.mjs +262 -0
- package/manager/utils/readBasePath.mjs +27 -0
- package/manager/utils/readBasePath.test.mjs +43 -0
- package/manager/utils/readBuildStatusWait.mjs +67 -0
- package/manager/utils/readManagerVersion.mjs +30 -0
- package/manager/utils/readManagerVersion.test.mjs +35 -0
- package/manager/utils/readPluginDefinitions.mjs +36 -0
- package/manager/utils/resolveDevAuthUrl.mjs +58 -0
- package/manager/utils/resolveDevAuthUrl.test.mjs +107 -0
- package/manager/utils/resolvePorts.mjs +49 -0
- package/manager/utils/setupWatcher.mjs +19 -11
- package/manager/utils/startRecordingPruner.mjs +45 -0
- package/manager/utils/startRecordingPruner.test.mjs +66 -0
- package/manager/utils/waitForChildExit.mjs +53 -0
- package/manager/utils/waitForChildExit.test.mjs +70 -0
- package/manager/utils/waitForServer.mjs +44 -0
- package/manager/utils/writeBuildStatus.mjs +1 -1
- package/manager/watchers/createPluginSourceIgnore.mjs +77 -0
- package/manager/watchers/envWatcher.mjs +9 -2
- package/manager/watchers/envWatcher.test.mjs +87 -0
- package/manager/watchers/listServerSidePackages.mjs +47 -0
- package/manager/watchers/listServerSidePackages.test.mjs +38 -0
- package/manager/watchers/lowdefyBuildWatcher.mjs +106 -22
- package/manager/watchers/lowdefyBuildWatcher.test.mjs +309 -0
- package/manager/watchers/pluginSourceWatcher.mjs +79 -0
- package/manager/watchers/pluginSourceWatcher.test.mjs +222 -0
- package/manager/watchers/restartRequestWatcher.mjs +71 -0
- package/manager/watchers/restartRequestWatcher.test.mjs +111 -0
- package/manager/watchers/selectLocalPluginPackages.mjs +48 -0
- package/manager/watchers/selectLocalPluginPackages.test.mjs +73 -0
- package/manager/watchers/serverPackageWatcher.mjs +38 -0
- package/package.json +60 -47
- package/package.original.json +60 -47
- package/src/app.js +131 -20
- package/src/html/renderDevPage.js +63 -11
- package/src/html/renderDevPage.test.mjs +138 -0
- package/src/lib/getRequestPath.js +29 -0
- package/src/middleware/createSameOriginGuard.js +37 -0
- package/src/middleware/createSameOriginGuard.test.mjs +102 -0
- package/src/middleware/errorHandler.js +51 -1
- package/src/middleware/errorHandler.test.mjs +173 -3
- package/src/middleware/isRebindingSafeHost.js +44 -0
- package/src/middleware/isRebindingSafeHost.test.mjs +32 -0
- package/src/middleware/localDevToolsOnly.js +38 -0
- package/src/middleware/localDevToolsOnly.test.mjs +61 -0
- package/src/middleware/noStore.js +27 -0
- package/src/middleware/noStore.test.mjs +48 -0
- package/src/middleware/requestTimeout.js +38 -0
- package/src/middleware/staleFlag.js +76 -0
- package/src/middleware/staleFlag.test.mjs +127 -0
- package/src/middleware/stampCaller.js +38 -0
- package/src/middleware/stampCaller.test.mjs +64 -0
- package/src/routes/agent.js +15 -3
- package/src/routes/auth.js +29 -20
- package/src/routes/auth.test.mjs +30 -56
- package/src/routes/clientError.js +13 -13
- package/src/routes/cron.js +3 -1
- package/src/routes/cronForward.js +3 -1
- package/src/routes/detached.js +22 -9
- package/src/routes/devInspect.js +17 -8
- package/src/routes/devInspect.test.mjs +44 -7
- package/src/routes/devRecording.js +113 -0
- package/src/routes/devRecording.test.mjs +253 -0
- package/src/routes/docs/buildStatus.js +10 -2
- package/src/routes/docs/buildStatus.test.mjs +46 -0
- package/src/routes/docs/content.js +5 -3
- package/src/routes/docs/evalOperator.js +15 -1
- package/src/routes/docs/events.js +50 -0
- package/src/routes/docs/events.test.mjs +117 -0
- package/src/routes/docs/find.js +9 -1
- package/src/routes/docs/icons.js +30 -0
- package/src/routes/docs/inspectState.js +16 -1
- package/src/routes/docs/journey.js +194 -0
- package/src/routes/docs/journey.test.mjs +401 -0
- package/src/routes/docs/journeyRefusals.test.mjs +71 -0
- package/src/routes/docs/loadState.js +4 -2
- package/src/routes/docs/mcp.js +34 -3
- package/src/routes/docs/mcp.test.mjs +130 -0
- package/src/routes/docs/mutants.js +78 -0
- package/src/routes/docs/mutants.test.mjs +180 -0
- package/src/routes/docs/parsePathParamsParam.js +41 -0
- package/src/routes/docs/parsePathParamsParam.test.mjs +42 -0
- package/src/routes/docs/parseUserParam.js +27 -21
- package/src/routes/docs/parseUserParam.test.mjs +17 -5
- package/src/routes/docs/restart.js +35 -0
- package/src/routes/docs/restart.test.mjs +64 -0
- package/src/routes/docs/runEndpoint.js +54 -0
- package/src/routes/docs/runEndpoint.test.mjs +165 -0
- package/src/routes/docs/runRequest.js +25 -8
- package/src/routes/docs/runRequest.test.mjs +92 -0
- package/src/routes/docs/screenshot.js +50 -2
- package/src/routes/docs/screenshot.test.mjs +117 -0
- package/src/routes/docs/search.js +15 -2
- package/src/routes/docs/snapshotState.js +17 -3
- package/src/routes/endpoints.js +27 -26
- package/src/routes/endpointsTextAnswer.test.mjs +77 -0
- package/src/routes/feedback.js +10 -13
- package/src/routes/jitPage.js +99 -35
- package/src/routes/jitPage.test.mjs +248 -0
- package/src/routes/mcp.js +82 -5
- package/src/routes/mcp.test.mjs +215 -0
- package/src/routes/mcpMemberToken.test.mjs +125 -0
- package/src/routes/mcpProtectedResourceMetadata.js +34 -0
- package/src/routes/mcpProtectedResourceMetadata.test.mjs +65 -0
- package/src/routes/mountDevPageRoutes.js +25 -0
- package/src/routes/mountDevPageRoutes.test.mjs +30 -0
- package/src/routes/mountOauthDiscovery.js +44 -0
- package/src/routes/mountOauthDiscovery.test.mjs +79 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.js +46 -0
- package/src/routes/normalizeMcpProtocolVersionHeader.test.mjs +62 -0
- package/src/routes/reload.js +16 -0
- package/src/routes/request.js +6 -4
- package/src/routes/request.test.mjs +9 -5
- package/src/routes/requestBody.test.mjs +159 -0
- package/src/routes/usage.js +6 -2
- package/src/routes/user.js +27 -0
- package/src/routes/websocket.js +29 -8
- package/src/routes/websocket.test.mjs +65 -0
- package/src/routes/wellKnownFallback.js +30 -0
- package/src/routes/wellKnownFallback.test.mjs +32 -0
- package/src/websocket/devWebSocket.js +41 -26
- package/src/websocket/devWebSocket.test.mjs +157 -0
- package/vite.config.js +53 -23
- package/lib/server/auth/getDevSession.js +0 -70
- package/lib/server/auth/getDevSession.test.mjs +0 -138
- package/manager/processes/warnAuthUrlPortMismatch.mjs +0 -47
- package/manager/processes/warnAuthUrlPortMismatch.test.mjs +0 -93
- package/manager/watchers/moduleBuildWatcher.mjs +0 -79
- package/manager/watchers/serverArtifactWatcher.mjs +0 -120
- package/src/routes/apiPage.js +0 -37
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { type } from '@lowdefy/helpers';
|
|
18
|
+
|
|
19
|
+
const EXPORT_KINDS = ['pages', 'components', 'menus', 'connections', 'api'];
|
|
20
|
+
|
|
21
|
+
// The build does not check every part of module.lowdefy.yaml this page reads
|
|
22
|
+
// (exports above all), so a part with the wrong shape is named on the page
|
|
23
|
+
// instead of failing every docs call that reads it.
|
|
24
|
+
function invalidLine({ label, expected, value, depth = 0 }) {
|
|
25
|
+
return `${' '.repeat(
|
|
26
|
+
depth
|
|
27
|
+
)}- ${label}: not valid in module.lowdefy.yaml, expected ${expected}. Received ${
|
|
28
|
+
JSON.stringify(value) ?? 'undefined'
|
|
29
|
+
}.`;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// A var default that is an operator, or a body the build defers, has no value
|
|
33
|
+
// until the module is built for a consumer.
|
|
34
|
+
function formatDefault(value) {
|
|
35
|
+
if (type.isObject(value)) {
|
|
36
|
+
const keys = Object.keys(value);
|
|
37
|
+
if (keys.some((key) => key === '~deferred') || (keys.length === 1 && keys[0].startsWith('_'))) {
|
|
38
|
+
return 'computed';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return `\`${JSON.stringify(value)}\``;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function varLines({ varDefs, prefix, depth }) {
|
|
45
|
+
const lines = [];
|
|
46
|
+
for (const [name, definition] of Object.entries(varDefs)) {
|
|
47
|
+
const fullName = prefix ? `${prefix}.${name}` : name;
|
|
48
|
+
if (!type.isObject(definition)) {
|
|
49
|
+
lines.push(
|
|
50
|
+
invalidLine({ label: `\`${fullName}\``, expected: 'an object', value: definition, depth })
|
|
51
|
+
);
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
const details = [];
|
|
55
|
+
if (!type.isNone(definition.type)) {
|
|
56
|
+
details.push(definition.type);
|
|
57
|
+
}
|
|
58
|
+
if (definition.required === true) {
|
|
59
|
+
details.push('required');
|
|
60
|
+
}
|
|
61
|
+
if (!type.isUndefined(definition.default)) {
|
|
62
|
+
details.push(`default ${formatDefault(definition.default)}`);
|
|
63
|
+
}
|
|
64
|
+
const detail = details.length > 0 ? ` (${details.join(', ')})` : '';
|
|
65
|
+
const description = type.isString(definition.description) ? `: ${definition.description}` : '';
|
|
66
|
+
lines.push(`${' '.repeat(depth)}- \`${fullName}\`${detail}${description}`);
|
|
67
|
+
if (type.isObject(definition.properties)) {
|
|
68
|
+
lines.push(
|
|
69
|
+
...varLines({ varDefs: definition.properties, prefix: fullName, depth: depth + 1 })
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return lines;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function idLines({ items, label }) {
|
|
77
|
+
if (type.isNone(items)) {
|
|
78
|
+
return [];
|
|
79
|
+
}
|
|
80
|
+
if (!type.isArray(items)) {
|
|
81
|
+
return [invalidLine({ label: `\`${label}\``, expected: 'a list', value: items })];
|
|
82
|
+
}
|
|
83
|
+
return items.map((item, index) => {
|
|
84
|
+
if (!type.isObject(item) || !type.isString(item.id)) {
|
|
85
|
+
return invalidLine({
|
|
86
|
+
label: `\`${label}.${index}\``,
|
|
87
|
+
expected: 'an object with a string id',
|
|
88
|
+
value: item,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
const description = type.isString(item.description) ? `: ${item.description}` : '';
|
|
92
|
+
return `- \`${item.id}\`${description}`;
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function componentLines({ manifest }) {
|
|
97
|
+
const exported = manifest.exports?.components;
|
|
98
|
+
const exportedDescriptions = new Map(
|
|
99
|
+
(type.isArray(exported) ? exported : [])
|
|
100
|
+
.filter((item) => type.isObject(item))
|
|
101
|
+
.map((item) => [item.id, item.description])
|
|
102
|
+
);
|
|
103
|
+
const components = manifest.components;
|
|
104
|
+
if (!type.isArray(components)) {
|
|
105
|
+
return idLines({ items: components, label: 'components' });
|
|
106
|
+
}
|
|
107
|
+
return idLines({
|
|
108
|
+
items: components.map((item) =>
|
|
109
|
+
type.isObject(item)
|
|
110
|
+
? { id: item.id, description: item.description ?? exportedDescriptions.get(item.id) }
|
|
111
|
+
: item
|
|
112
|
+
),
|
|
113
|
+
label: 'components',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function exportLines({ manifest }) {
|
|
118
|
+
const moduleExports = manifest.exports;
|
|
119
|
+
if (type.isNone(moduleExports)) {
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
if (!type.isObject(moduleExports)) {
|
|
123
|
+
return [invalidLine({ label: '`exports`', expected: 'an object', value: moduleExports }), ''];
|
|
124
|
+
}
|
|
125
|
+
const lines = [];
|
|
126
|
+
for (const kind of EXPORT_KINDS) {
|
|
127
|
+
const items = idLines({ items: moduleExports[kind], label: `exports.${kind}` });
|
|
128
|
+
if (items.length > 0) {
|
|
129
|
+
lines.push(`### ${kind}`, '', ...items, '');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return lines;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// The interface a module declares in module.lowdefy.yaml, as markdown.
|
|
136
|
+
function makeModuleManifestDoc({ moduleEntry }) {
|
|
137
|
+
const manifest = type.isObject(moduleEntry.manifest) ? moduleEntry.manifest : {};
|
|
138
|
+
const lines = [`# ${moduleEntry.id} module: components, exports and vars`, ''];
|
|
139
|
+
if (type.isString(manifest.name)) {
|
|
140
|
+
lines.push(`**${manifest.name}**`, '');
|
|
141
|
+
}
|
|
142
|
+
if (type.isString(manifest.description)) {
|
|
143
|
+
lines.push(manifest.description, '');
|
|
144
|
+
}
|
|
145
|
+
lines.push(
|
|
146
|
+
`Source: \`${moduleEntry.source}\`. Module id in this app: \`${moduleEntry.id}\`.`,
|
|
147
|
+
''
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
lines.push('## Vars', '');
|
|
151
|
+
const varDefs = moduleEntry.varDefs ?? {};
|
|
152
|
+
let vars;
|
|
153
|
+
if (type.isObject(varDefs)) {
|
|
154
|
+
vars = varLines({ varDefs, prefix: '', depth: 0 });
|
|
155
|
+
} else {
|
|
156
|
+
vars = [invalidLine({ label: '`vars`', expected: 'an object', value: varDefs })];
|
|
157
|
+
}
|
|
158
|
+
lines.push(...(vars.length > 0 ? vars : ['None declared.']), '');
|
|
159
|
+
lines.push(
|
|
160
|
+
`Set vars in lowdefy.yaml under \`modules\`, on the entry with \`id: ${moduleEntry.id}\`.`,
|
|
161
|
+
''
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
lines.push('## Components', '');
|
|
165
|
+
const components = componentLines({ manifest });
|
|
166
|
+
lines.push(...(components.length > 0 ? components : ['None declared.']), '');
|
|
167
|
+
|
|
168
|
+
lines.push('## Exports', '');
|
|
169
|
+
const exportsSection = exportLines({ manifest });
|
|
170
|
+
lines.push(...(exportsSection.length > 0 ? exportsSection : ['None declared.', '']));
|
|
171
|
+
return lines.join('\n');
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export default makeModuleManifestDoc;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { type } from '@lowdefy/helpers';
|
|
18
|
+
import { matchPagePath } from '@lowdefy/node-utils';
|
|
19
|
+
|
|
20
|
+
// The page ids behind the request paths a journey's browsers loaded, matched
|
|
21
|
+
// through the route table the way the page route matches them, so every
|
|
22
|
+
// instance of a patterned page names the one page. A path no page answers
|
|
23
|
+
// names none.
|
|
24
|
+
function matchExercisedPages({ routes, pagePaths }) {
|
|
25
|
+
const pageIds = new Set();
|
|
26
|
+
pagePaths.forEach((path) => {
|
|
27
|
+
const match = matchPagePath({ routes, path });
|
|
28
|
+
if (!type.isNone(match)) {
|
|
29
|
+
pageIds.add(match.pageId);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
return [...pageIds].sort();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default matchExercisedPages;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
function decodeSegments(text) {
|
|
18
|
+
return text
|
|
19
|
+
.split('/')
|
|
20
|
+
.filter((segment) => segment !== '')
|
|
21
|
+
.map((segment) => decodeURIComponent(segment));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Names the dev server route a journey's browser request hit, from its URL
|
|
25
|
+
// and method, with the app's basePath honoured. A page request carries its
|
|
26
|
+
// request path, which collectExercised matches to a page id through the route
|
|
27
|
+
// table. Requests to other origins and to every other route are null.
|
|
28
|
+
function matchJourneyRoute({ url, method, origin, basePath = '' }) {
|
|
29
|
+
const parsed = new URL(url);
|
|
30
|
+
if (parsed.origin !== origin) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const prefix = `${basePath}/api/`;
|
|
34
|
+
if (!parsed.pathname.startsWith(prefix)) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const rest = parsed.pathname.slice(prefix.length);
|
|
38
|
+
if (rest === 'root' && method === 'GET') {
|
|
39
|
+
return { route: 'root' };
|
|
40
|
+
}
|
|
41
|
+
if (rest.startsWith('page/') && method === 'GET') {
|
|
42
|
+
const path = rest.slice('page/'.length);
|
|
43
|
+
if (path === '') {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
return { route: 'page', path };
|
|
47
|
+
}
|
|
48
|
+
if (rest.startsWith('request/') && method === 'POST') {
|
|
49
|
+
const segments = decodeSegments(rest.slice('request/'.length));
|
|
50
|
+
if (segments.length < 2) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
route: 'request',
|
|
55
|
+
pageId: segments.slice(0, -1).join('/'),
|
|
56
|
+
requestId: segments[segments.length - 1],
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (rest.startsWith('endpoints/')) {
|
|
60
|
+
const segments = decodeSegments(rest.slice('endpoints/'.length));
|
|
61
|
+
if (segments.length === 0) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
return { route: 'endpoint', endpointId: segments.join('/') };
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export default matchJourneyRoute;
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import createNetworkCounter from './createNetworkCounter.js';
|
|
18
|
+
import matchExercisedPages from './matchExercisedPages.js';
|
|
19
|
+
import matchJourneyRoute from './matchJourneyRoute.js';
|
|
20
|
+
import mergeNetworkSnapshots from './mergeNetworkSnapshots.js';
|
|
21
|
+
import nextJourneySequence from './nextJourneySequence.js';
|
|
22
|
+
|
|
23
|
+
const origin = 'http://localhost:3111';
|
|
24
|
+
|
|
25
|
+
test.each([
|
|
26
|
+
['GET', '/api/root', { route: 'root' }],
|
|
27
|
+
['GET', '/api/page/tickets', { route: 'page', path: 'tickets' }],
|
|
28
|
+
['GET', '/api/page/admin/users', { route: 'page', path: 'admin/users' }],
|
|
29
|
+
['GET', '/api/page/tickets/s/2', { route: 'page', path: 'tickets/s/2' }],
|
|
30
|
+
['GET', '/api/page/', null],
|
|
31
|
+
[
|
|
32
|
+
'POST',
|
|
33
|
+
'/api/request/tickets/assign',
|
|
34
|
+
{ route: 'request', pageId: 'tickets', requestId: 'assign' },
|
|
35
|
+
],
|
|
36
|
+
['POST', '/api/endpoints/notify', { route: 'endpoint', endpointId: 'notify' }],
|
|
37
|
+
['GET', '/api/endpoints/reports/daily', { route: 'endpoint', endpointId: 'reports/daily' }],
|
|
38
|
+
['POST', '/api/root', null],
|
|
39
|
+
['GET', '/api/request/tickets/assign', null],
|
|
40
|
+
['POST', '/api/request/tickets', null],
|
|
41
|
+
['GET', '/api/reload', null],
|
|
42
|
+
['GET', '/tickets', null],
|
|
43
|
+
])('matchJourneyRoute matches %s %s', (method, pathname, expected) => {
|
|
44
|
+
expect(matchJourneyRoute({ url: `${origin}${pathname}`, method, origin })).toEqual(expected);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('matchJourneyRoute honours the basePath and ignores paths outside it', () => {
|
|
48
|
+
expect(
|
|
49
|
+
matchJourneyRoute({
|
|
50
|
+
url: `${origin}/app/api/page/home`,
|
|
51
|
+
method: 'GET',
|
|
52
|
+
origin,
|
|
53
|
+
basePath: '/app',
|
|
54
|
+
})
|
|
55
|
+
).toEqual({ route: 'page', path: 'home' });
|
|
56
|
+
expect(
|
|
57
|
+
matchJourneyRoute({
|
|
58
|
+
url: `${origin}/app/api/page/tickets/s/2?tab=notes`,
|
|
59
|
+
method: 'GET',
|
|
60
|
+
origin,
|
|
61
|
+
basePath: '/app',
|
|
62
|
+
})
|
|
63
|
+
).toEqual({ route: 'page', path: 'tickets/s/2' });
|
|
64
|
+
expect(
|
|
65
|
+
matchJourneyRoute({ url: `${origin}/api/page/home`, method: 'GET', origin, basePath: '/app' })
|
|
66
|
+
).toBeNull();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test('matchJourneyRoute ignores requests to another origin', () => {
|
|
70
|
+
expect(
|
|
71
|
+
matchJourneyRoute({ url: 'http://elsewhere.test/api/page/home', method: 'GET', origin })
|
|
72
|
+
).toBeNull();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
function request(method, pathname) {
|
|
76
|
+
return { method: () => method, url: () => `${origin}${pathname}` };
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
test('createNetworkCounter counts request calls per page and endpoint calls', () => {
|
|
80
|
+
const counter = createNetworkCounter({ origin, basePath: '' });
|
|
81
|
+
counter.record(request('GET', '/api/root'));
|
|
82
|
+
counter.record(request('GET', '/api/page/tickets'));
|
|
83
|
+
counter.record(request('GET', '/api/page/tickets/s/2'));
|
|
84
|
+
counter.record(request('POST', '/api/request/tickets/save'));
|
|
85
|
+
counter.record(request('POST', '/api/request/tickets/save'));
|
|
86
|
+
counter.record(request('POST', '/api/request/ticket/save'));
|
|
87
|
+
counter.record(request('POST', '/api/endpoints/notify'));
|
|
88
|
+
expect(counter.countCalls({ request: 'save', pageId: 'tickets' })).toEqual(2);
|
|
89
|
+
expect(counter.countCalls({ request: 'save', pageId: 'ticket' })).toEqual(1);
|
|
90
|
+
expect(counter.countCalls({ request: 'save', pageId: 'other' })).toEqual(0);
|
|
91
|
+
expect(counter.countCalls({ endpoint: 'notify' })).toEqual(1);
|
|
92
|
+
expect(counter.countCalls({ endpoint: 'other' })).toEqual(0);
|
|
93
|
+
expect(counter.snapshot()).toEqual({
|
|
94
|
+
pagePaths: ['tickets', 'tickets/s/2'],
|
|
95
|
+
appEvents: true,
|
|
96
|
+
requests: [
|
|
97
|
+
{ pageId: 'tickets', requestId: 'save', calls: 2 },
|
|
98
|
+
{ pageId: 'ticket', requestId: 'save', calls: 1 },
|
|
99
|
+
],
|
|
100
|
+
endpoints: [{ endpointId: 'notify', calls: 1 }],
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('mergeNetworkSnapshots sums calls across actors and sorts the result', () => {
|
|
105
|
+
expect(
|
|
106
|
+
mergeNetworkSnapshots({
|
|
107
|
+
snapshots: [
|
|
108
|
+
{
|
|
109
|
+
pagePaths: ['tickets/s/2'],
|
|
110
|
+
appEvents: true,
|
|
111
|
+
requests: [{ pageId: 'tickets', requestId: 'save', calls: 1 }],
|
|
112
|
+
endpoints: [{ endpointId: 'notify', calls: 1 }],
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
pagePaths: ['home', 'tickets/s/2', 'tickets/s/5'],
|
|
116
|
+
appEvents: false,
|
|
117
|
+
requests: [
|
|
118
|
+
{ pageId: 'tickets', requestId: 'save', calls: 2 },
|
|
119
|
+
{ pageId: 'home', requestId: 'load', calls: 1 },
|
|
120
|
+
],
|
|
121
|
+
endpoints: [{ endpointId: 'notify', calls: 3 }],
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
})
|
|
125
|
+
).toEqual({
|
|
126
|
+
pagePaths: ['home', 'tickets/s/2', 'tickets/s/5'],
|
|
127
|
+
appEvents: true,
|
|
128
|
+
requests: [
|
|
129
|
+
{ pageId: 'home', requestId: 'load', calls: 1 },
|
|
130
|
+
{ pageId: 'tickets', requestId: 'save', calls: 3 },
|
|
131
|
+
],
|
|
132
|
+
endpoints: [{ endpointId: 'notify', calls: 4 }],
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const routes = [
|
|
137
|
+
{ pageId: 'home', path: 'home' },
|
|
138
|
+
{ pageId: 'ticket', path: 'tickets/{space}/{ticket_id}' },
|
|
139
|
+
{ pageId: 'admin/users', path: 'people' },
|
|
140
|
+
];
|
|
141
|
+
|
|
142
|
+
test('matchExercisedPages names a patterned page once for all of its instances', () => {
|
|
143
|
+
expect(
|
|
144
|
+
matchExercisedPages({ routes, pagePaths: ['tickets/s/2', 'tickets/s/5', 'home'] })
|
|
145
|
+
).toEqual(['home', 'ticket']);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
test('matchExercisedPages names a page with a fixed path by its id', () => {
|
|
149
|
+
expect(matchExercisedPages({ routes, pagePaths: ['people'] })).toEqual(['admin/users']);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test('matchExercisedPages drops a path no page answers', () => {
|
|
153
|
+
expect(matchExercisedPages({ routes, pagePaths: ['admin/users', 'missing'] })).toEqual([]);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
test('a journey under a basePath reports page ids for the page paths it loaded', () => {
|
|
157
|
+
const counter = createNetworkCounter({ origin, basePath: '/app' });
|
|
158
|
+
counter.record(request('GET', '/app/api/page/tickets/s/2'));
|
|
159
|
+
counter.record(request('GET', '/app/api/page/people'));
|
|
160
|
+
counter.record(request('GET', '/api/page/home'));
|
|
161
|
+
expect(
|
|
162
|
+
matchExercisedPages({
|
|
163
|
+
routes,
|
|
164
|
+
pagePaths: mergeNetworkSnapshots({ snapshots: [counter.snapshot()] }).pagePaths,
|
|
165
|
+
})
|
|
166
|
+
).toEqual(['admin/users', 'ticket']);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test('the network counter tells a request call made after a point from one made before it', () => {
|
|
170
|
+
const counter = createNetworkCounter({ origin, basePath: '' });
|
|
171
|
+
const call = { url: () => `${origin}/api/request/form/save`, method: () => 'POST' };
|
|
172
|
+
const beforeCall = nextJourneySequence();
|
|
173
|
+
counter.record(call);
|
|
174
|
+
const afterCall = nextJourneySequence();
|
|
175
|
+
expect(counter.calledSince({ request: 'save', pageId: 'form', since: beforeCall })).toBe(true);
|
|
176
|
+
expect(counter.calledSince({ request: 'save', pageId: 'form', since: afterCall })).toBe(false);
|
|
177
|
+
expect(counter.calledSince({ request: 'load', pageId: 'form', since: 0 })).toBe(false);
|
|
178
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// One journey's network path across all of its actors: the request path of a
|
|
18
|
+
// page any actor loaded, and each request or endpoint with the calls of every actor summed.
|
|
19
|
+
function mergeNetworkSnapshots({ snapshots }) {
|
|
20
|
+
const pagePaths = new Set();
|
|
21
|
+
const requests = new Map();
|
|
22
|
+
const endpoints = new Map();
|
|
23
|
+
let appEvents = false;
|
|
24
|
+
snapshots.forEach((snapshot) => {
|
|
25
|
+
snapshot.pagePaths.forEach((path) => pagePaths.add(path));
|
|
26
|
+
appEvents = appEvents || snapshot.appEvents;
|
|
27
|
+
snapshot.requests.forEach(({ pageId, requestId, calls }) => {
|
|
28
|
+
const key = JSON.stringify([pageId, requestId]);
|
|
29
|
+
const entry = requests.get(key) ?? { pageId, requestId, calls: 0 };
|
|
30
|
+
entry.calls += calls;
|
|
31
|
+
requests.set(key, entry);
|
|
32
|
+
});
|
|
33
|
+
snapshot.endpoints.forEach(({ endpointId, calls }) => {
|
|
34
|
+
endpoints.set(endpointId, (endpoints.get(endpointId) ?? 0) + calls);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
return {
|
|
38
|
+
pagePaths: [...pagePaths].sort(),
|
|
39
|
+
appEvents,
|
|
40
|
+
requests: [...requests.values()].sort(
|
|
41
|
+
(a, b) => a.pageId.localeCompare(b.pageId) || a.requestId.localeCompare(b.requestId)
|
|
42
|
+
),
|
|
43
|
+
endpoints: [...endpoints.entries()]
|
|
44
|
+
.map(([endpointId, calls]) => ({ endpointId, calls }))
|
|
45
|
+
.sort((a, b) => a.endpointId.localeCompare(b.endpointId)),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export default mergeNetworkSnapshots;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// One ordering for every journey's network events and step windows in this
|
|
18
|
+
// process. A clock can give a call and the step after it the same millisecond;
|
|
19
|
+
// a sequence cannot, so "started since the step began" is never a tie. Kept on
|
|
20
|
+
// globalThis, as journeyActor.js keeps its token, so two module instances of
|
|
21
|
+
// this file (Vite's SSR module graph and Node's) still share one order.
|
|
22
|
+
const SEQUENCE_KEY = Symbol.for('lowdefy.devServer.journeySequence');
|
|
23
|
+
globalThis[SEQUENCE_KEY] ??= 0;
|
|
24
|
+
|
|
25
|
+
function nextJourneySequence() {
|
|
26
|
+
globalThis[SEQUENCE_KEY] += 1;
|
|
27
|
+
return globalThis[SEQUENCE_KEY];
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default nextJourneySequence;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// The message every browser tool returns when getBrowser() fails.
|
|
18
|
+
function noBrowserError(error) {
|
|
19
|
+
return `No Chromium available. Run: npx playwright install chromium-headless-shell (the dev server installs it on first use unless PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD is set). ${error.message}`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default noBrowserError;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// antd's click wave: inserted into a clicked Button and removed when its
|
|
18
|
+
// motion ends, so a step window's mutation count never counts it.
|
|
19
|
+
const TRANSIENT_SELECTOR = '.ant-wave';
|
|
20
|
+
|
|
21
|
+
export default TRANSIENT_SELECTOR;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2026 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import toAppErrorFailure from './toAppErrorFailure.js';
|
|
18
|
+
|
|
19
|
+
function describeErrors(findings) {
|
|
20
|
+
if (findings.length === 0) {
|
|
21
|
+
return 'no app error';
|
|
22
|
+
}
|
|
23
|
+
return findings.map((finding) => `${finding.kind}: ${finding.message}`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function matches({ finding, text }) {
|
|
27
|
+
return String(finding.message).includes(text);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// An expect.error step claims the app errors of the interaction just before
|
|
31
|
+
// it (held) and of its own window whose message contains its text. Returns
|
|
32
|
+
// the failure, or undefined when the claim passes: the expect step fails when
|
|
33
|
+
// no error matches, and the interaction fails on any error left unclaimed.
|
|
34
|
+
//
|
|
35
|
+
// An action-error is the trace's account of the action that failed, and the
|
|
36
|
+
// trace is value-free: its message names the action and the error class, never
|
|
37
|
+
// the error's text. So once an error with the text is claimed, the failed
|
|
38
|
+
// action that reported it is claimed with it. An event stops at its first
|
|
39
|
+
// failed action, so this claims no second, unrelated failure of the event.
|
|
40
|
+
function claimExpectedErrors({ step, index, held, findings }) {
|
|
41
|
+
const text = step.expect.error;
|
|
42
|
+
const seen = [...(held?.findings ?? []), ...findings];
|
|
43
|
+
const matched = seen.filter((finding) => matches({ finding, text }));
|
|
44
|
+
const claimed =
|
|
45
|
+
matched.length === 0
|
|
46
|
+
? []
|
|
47
|
+
: seen.filter((finding) => matches({ finding, text }) || finding.kind === 'action-error');
|
|
48
|
+
if (claimed.length === 0) {
|
|
49
|
+
const actual = describeErrors(seen);
|
|
50
|
+
return {
|
|
51
|
+
index,
|
|
52
|
+
step,
|
|
53
|
+
expected: `an app error containing "${text}"`,
|
|
54
|
+
actual,
|
|
55
|
+
message: `Expected an app error containing "${text}" but found ${
|
|
56
|
+
seen.length === 0 ? 'no app error.' : actual.join('; ')
|
|
57
|
+
}`,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const unclaimed = seen.filter((finding) => !claimed.includes(finding));
|
|
61
|
+
if (unclaimed.length === 0) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
return toAppErrorFailure({ findings: unclaimed, index: held.index, step: held.step });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default claimExpectedErrors;
|