@intuned/browser-dev 0.1.4-dev.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/.babelrc +21 -0
- package/.eslintignore +10 -0
- package/.eslintrc.js +39 -0
- package/BROWSER_SCRIPTS_SETUP.md +84 -0
- package/LICENSE +43 -0
- package/README.md +160 -0
- package/RELEASE.md +60 -0
- package/dist/ai/export.d.js +5 -0
- package/dist/ai/export.d.ts +641 -0
- package/dist/ai/extractStructuredData.js +320 -0
- package/dist/ai/extractStructuredDataUsingAi.js +142 -0
- package/dist/ai/extractionHelpers/screenshotHelpers.js +56 -0
- package/dist/ai/extractionHelpers/validateSchema.js +148 -0
- package/dist/ai/index.d.ts +641 -0
- package/dist/ai/index.js +19 -0
- package/dist/ai/isPageLoaded.js +80 -0
- package/dist/ai/prompt.js +39 -0
- package/dist/ai/tests/testCheckAllTypesAreStrings.spec.js +137 -0
- package/dist/ai/tests/testExtractFromContent.spec.js +372 -0
- package/dist/ai/tests/testExtractStructuredData.spec.js +646 -0
- package/dist/ai/tests/testIsPageLoaded.spec.js +277 -0
- package/dist/ai/tools/index.js +48 -0
- package/dist/ai/types/errors.js +67 -0
- package/dist/ai/types/models.js +45 -0
- package/dist/ai/types/types.js +48 -0
- package/dist/ai/validators.js +167 -0
- package/dist/common/Logger/index.js +60 -0
- package/dist/common/Logger/types.js +5 -0
- package/dist/common/SdkError.js +50 -0
- package/dist/common/aiModelsValidations.js +32 -0
- package/dist/common/ensureBrowserScripts.js +14 -0
- package/dist/common/extendedTest.js +157 -0
- package/dist/common/extractionHelpers.js +19 -0
- package/dist/common/formatZodError.js +18 -0
- package/dist/common/fuzzySearch/fuzzySearch.test.js +250 -0
- package/dist/common/fuzzySearch/levenshtein-search.js +298 -0
- package/dist/common/fuzzySearch/utils.js +23 -0
- package/dist/common/getModelProvider.js +18 -0
- package/dist/common/getSimplifiedHtml.js +122 -0
- package/dist/common/hashObject.js +32 -0
- package/dist/common/html2markdown/convertElementToMarkdown.js +469 -0
- package/dist/common/html2markdown/index.js +19 -0
- package/dist/common/jwtTokenManager.js +57 -0
- package/dist/common/loadRuntime.js +16 -0
- package/dist/common/locatorHelpers.js +41 -0
- package/dist/common/matching/collectStrings.js +32 -0
- package/dist/common/matching/levenshtein.js +40 -0
- package/dist/common/matching/matching.js +317 -0
- package/dist/common/matching/types.js +1 -0
- package/dist/common/noEmpty.js +9 -0
- package/dist/common/saveSnapshotWithExamples.js +60 -0
- package/dist/common/script.js +2602 -0
- package/dist/common/tests/testEnsureBrowserScript.spec.js +31 -0
- package/dist/common/xpathMapping.js +107 -0
- package/dist/helpers/clickUntilExhausted.js +85 -0
- package/dist/helpers/downloadFile.js +125 -0
- package/dist/helpers/export.d.js +5 -0
- package/dist/helpers/export.d.ts +1220 -0
- package/dist/helpers/extractMarkdown.js +35 -0
- package/dist/helpers/filterEmptyValues.js +54 -0
- package/dist/helpers/gotoUrl.js +98 -0
- package/dist/helpers/index.d.ts +1220 -0
- package/dist/helpers/index.js +122 -0
- package/dist/helpers/processDate.js +25 -0
- package/dist/helpers/resolveUrl.js +64 -0
- package/dist/helpers/sanitizeHtml.js +74 -0
- package/dist/helpers/saveFileToS3.js +50 -0
- package/dist/helpers/scrollToLoadContent.js +57 -0
- package/dist/helpers/tests/testClickUntilExhausted.spec.js +372 -0
- package/dist/helpers/tests/testDownloadFile.spec.js +206 -0
- package/dist/helpers/tests/testExtractMarkdown.spec.js +290 -0
- package/dist/helpers/tests/testFilterEmptyValues.spec.js +151 -0
- package/dist/helpers/tests/testGoToUrl.spec.js +37 -0
- package/dist/helpers/tests/testProcessDate.spec.js +13 -0
- package/dist/helpers/tests/testResolveUrl.spec.js +341 -0
- package/dist/helpers/tests/testSanitizeHtml.spec.js +330 -0
- package/dist/helpers/tests/testScrollToLoadContent.spec.js +163 -0
- package/dist/helpers/tests/testValidateDataUsingSchema.spec.js +342 -0
- package/dist/helpers/tests/testWithDomSettledWait.spec.js +164 -0
- package/dist/helpers/tests/testWithNetworkIdleWait.spec.js +114 -0
- package/dist/helpers/types/Attachment.js +115 -0
- package/dist/helpers/types/CustomTypeRegistry.js +48 -0
- package/dist/helpers/types/RunEnvironment.js +18 -0
- package/dist/helpers/types/ValidationError.js +17 -0
- package/dist/helpers/types/index.js +51 -0
- package/dist/helpers/uploadFileToS3.js +154 -0
- package/dist/helpers/utils/getS3Client.js +22 -0
- package/dist/helpers/utils/index.js +73 -0
- package/dist/helpers/utils/isDownload.js +10 -0
- package/dist/helpers/utils/isGenerateCodeMode.js +9 -0
- package/dist/helpers/utils/isLocator.js +9 -0
- package/dist/helpers/utils/jwtTokenManager.js +18 -0
- package/dist/helpers/validateDataUsingSchema.js +103 -0
- package/dist/helpers/waitForDomSettled.js +90 -0
- package/dist/helpers/withNetworkSettledWait.js +91 -0
- package/dist/index.d.js +16 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +16 -0
- package/dist/intunedServices/ApiGateway/aiApiGateway.js +143 -0
- package/dist/intunedServices/ApiGateway/factory.js +16 -0
- package/dist/intunedServices/ApiGateway/providers/Anthropic.js +26 -0
- package/dist/intunedServices/ApiGateway/providers/Gemini.js +29 -0
- package/dist/intunedServices/ApiGateway/providers/OpenAI.js +29 -0
- package/dist/intunedServices/ApiGateway/tests/testApiGateway.spec.js +355 -0
- package/dist/intunedServices/ApiGateway/types.js +11 -0
- package/dist/intunedServices/cache/cache.js +61 -0
- package/dist/intunedServices/cache/index.js +12 -0
- package/dist/intunedServices/cache/tests/testCache.spec.js +117 -0
- package/dist/optimized-extractors/common/buildExamplesPrompt.js +12 -0
- package/dist/optimized-extractors/common/buildImagesFromPage.js +55 -0
- package/dist/optimized-extractors/common/extractStructuredDataUsingClaude.js +135 -0
- package/dist/optimized-extractors/common/extractStructuredDataUsingGoogle.js +37 -0
- package/dist/optimized-extractors/common/extractStructuredDataUsingOpenAi.js +132 -0
- package/dist/optimized-extractors/common/extractStrucutredDataUsingAiInstance.js +122 -0
- package/dist/optimized-extractors/common/findTableHeaders.js +162 -0
- package/dist/optimized-extractors/common/index.js +55 -0
- package/dist/optimized-extractors/common/isTableHeaderOrFooter.js +84 -0
- package/dist/optimized-extractors/common/matching/matching.js +212 -0
- package/dist/optimized-extractors/common/matching/matching.test.js +655 -0
- package/dist/optimized-extractors/common/matching/types.js +18 -0
- package/dist/optimized-extractors/common/matching/utils.js +184 -0
- package/dist/optimized-extractors/common/utils.js +58 -0
- package/dist/optimized-extractors/export.d.js +5 -0
- package/dist/optimized-extractors/export.d.ts +397 -0
- package/dist/optimized-extractors/extractArray.js +120 -0
- package/dist/optimized-extractors/extractObject.js +104 -0
- package/dist/optimized-extractors/index.d.ts +397 -0
- package/dist/optimized-extractors/index.js +31 -0
- package/dist/optimized-extractors/listExtractionHelpers/__tests__/dynamicListExtractor.spec.js +269 -0
- package/dist/optimized-extractors/listExtractionHelpers/__tests__/findSetOfXpathsToCreateAnArrayExtractor.test.js +22 -0
- package/dist/optimized-extractors/listExtractionHelpers/__tests__/getContainerElement.test.js +21 -0
- package/dist/optimized-extractors/listExtractionHelpers/__tests__/partOfSameArrayXpath.test.js +42 -0
- package/dist/optimized-extractors/listExtractionHelpers/__tests__/testArrayExtractorFromLocator.spec.js +146 -0
- package/dist/optimized-extractors/listExtractionHelpers/__tests__/testArrayExtractorFromPage.spec.js +130 -0
- package/dist/optimized-extractors/listExtractionHelpers/__tests__/verifyThatAllXpathsArePartOfSameArray.test.js +9 -0
- package/dist/optimized-extractors/listExtractionHelpers/dynamicListExtractor.js +160 -0
- package/dist/optimized-extractors/listExtractionHelpers/errors.js +46 -0
- package/dist/optimized-extractors/listExtractionHelpers/getListMatches.js +14 -0
- package/dist/optimized-extractors/listExtractionHelpers/runAiExtraction.js +243 -0
- package/dist/optimized-extractors/listExtractionHelpers/typesAndSchema.js +5 -0
- package/dist/optimized-extractors/listExtractionHelpers/utils/extractPropertiesUsingGPTFromArray.js +277 -0
- package/dist/optimized-extractors/listExtractionHelpers/utils/extractStructuredListUsingAi.js +44 -0
- package/dist/optimized-extractors/listExtractionHelpers/utils/getListContainerXpath.js +94 -0
- package/dist/optimized-extractors/listExtractionHelpers/utils/getRelativeContainerXpathSelector.js +20 -0
- package/dist/optimized-extractors/listExtractionHelpers/utils/getSimplifiedHtmlPerListItem.js +21 -0
- package/dist/optimized-extractors/listExtractionHelpers/utils/tablesUtils.js +48 -0
- package/dist/optimized-extractors/listExtractionHelpers/utils/validateOptions.js +52 -0
- package/dist/optimized-extractors/models/anthropicModel.js +23 -0
- package/dist/optimized-extractors/models/openaiModel.js +23 -0
- package/dist/optimized-extractors/objectExtractionHelpers/AIExtractors.js +73 -0
- package/dist/optimized-extractors/objectExtractionHelpers/__tests__/checksumUtils.test.js +103 -0
- package/dist/optimized-extractors/objectExtractionHelpers/__tests__/testObjectExtractorFromLocator.spec.js +107 -0
- package/dist/optimized-extractors/objectExtractionHelpers/__tests__/testObjectExtractorFromPage.spec.js +107 -0
- package/dist/optimized-extractors/objectExtractionHelpers/calculateObjectExampleHash.js +28 -0
- package/dist/optimized-extractors/objectExtractionHelpers/captureSnapshot.js +26 -0
- package/dist/optimized-extractors/objectExtractionHelpers/checksumUtils.js +32 -0
- package/dist/optimized-extractors/objectExtractionHelpers/constants.js +7 -0
- package/dist/optimized-extractors/objectExtractionHelpers/dynamicObjectExtractor.js +106 -0
- package/dist/optimized-extractors/objectExtractionHelpers/errors.js +42 -0
- package/dist/optimized-extractors/objectExtractionHelpers/findDomMatches.js +54 -0
- package/dist/optimized-extractors/objectExtractionHelpers/getSimplifiedHtml.js +122 -0
- package/dist/optimized-extractors/objectExtractionHelpers/typesAndSchemas.js +5 -0
- package/dist/optimized-extractors/objectExtractionHelpers/validateDynamicObjectExtractorOptions.js +52 -0
- package/dist/optimized-extractors/types/aiModelsValidation.js +45 -0
- package/dist/optimized-extractors/types/errors.js +42 -0
- package/dist/optimized-extractors/types/jsonSchema.d.js +5 -0
- package/dist/optimized-extractors/types/jsonSchema.d.ts +50 -0
- package/dist/optimized-extractors/types/types.js +5 -0
- package/dist/optimized-extractors/validators.js +152 -0
- package/dist/types/intuned-runtime.d.js +1 -0
- package/dist/types/intuned-runtime.d.ts +64 -0
- package/dist/vite-env.d.js +1 -0
- package/dist/vite-env.d.ts +9 -0
- package/generated-docs/ai/functions/extractStructuredData.mdx +255 -0
- package/generated-docs/ai/functions/isPageLoaded.mdx +88 -0
- package/generated-docs/ai/interfaces/ArraySchema.mdx +36 -0
- package/generated-docs/ai/interfaces/BasicSchema.mdx +14 -0
- package/generated-docs/ai/interfaces/BooleanSchema.mdx +28 -0
- package/generated-docs/ai/interfaces/ImageBufferContentItem.mdx +16 -0
- package/generated-docs/ai/interfaces/ImageUrlContentItem.mdx +16 -0
- package/generated-docs/ai/interfaces/NumberSchema.mdx +35 -0
- package/generated-docs/ai/interfaces/ObjectSchema.mdx +39 -0
- package/generated-docs/ai/interfaces/StringSchema.mdx +35 -0
- package/generated-docs/ai/interfaces/TextContentItem.mdx +14 -0
- package/generated-docs/ai/type-aliases/ContentItem.mdx +12 -0
- package/generated-docs/ai/type-aliases/JsonSchema.mdx +47 -0
- package/generated-docs/ai/type-aliases/SUPPORTED_MODELS.mdx +85 -0
- package/generated-docs/helpers/functions/downloadFile.mdx +99 -0
- package/generated-docs/helpers/functions/extractMarkdown.mdx +56 -0
- package/generated-docs/helpers/functions/filterEmptyValues.mdx +51 -0
- package/generated-docs/helpers/functions/goToUrl.mdx +124 -0
- package/generated-docs/helpers/functions/processDate.mdx +55 -0
- package/generated-docs/helpers/functions/resolveUrl.mdx +165 -0
- package/generated-docs/helpers/functions/sanitizeHtml.mdx +113 -0
- package/generated-docs/helpers/functions/saveFileToS3.mdx +127 -0
- package/generated-docs/helpers/functions/scrollToLoadContent.mdx +89 -0
- package/generated-docs/helpers/functions/uploadFileToS3.mdx +121 -0
- package/generated-docs/helpers/functions/validateDataUsingSchema.mdx +90 -0
- package/generated-docs/helpers/functions/waitForDomSettled.mdx +91 -0
- package/generated-docs/helpers/functions/withNetworkSettledWait.mdx +76 -0
- package/generated-docs/helpers/interfaces/Attachment.mdx +56 -0
- package/generated-docs/helpers/interfaces/S3Configs.mdx +52 -0
- package/generated-docs/helpers/interfaces/SanitizeHtmlOptions.mdx +22 -0
- package/generated-docs/helpers/type-aliases/AttachmentType.mdx +10 -0
- package/generated-docs/helpers/type-aliases/FileType.mdx +61 -0
- package/generated-docs/helpers/type-aliases/Trigger.mdx +62 -0
- package/how-to-generate-docs.md +61 -0
- package/how-to-run-tests.md +42 -0
- package/intuned-runtime-setup.md +13 -0
- package/package.json +124 -0
- package/tsconfig.eslint.json +5 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _extendedTest = require("../extendedTest");
|
|
4
|
+
var _ensureBrowserScripts = require("../ensureBrowserScripts");
|
|
5
|
+
var _playwright = require("playwright");
|
|
6
|
+
var _dotenv = require("dotenv");
|
|
7
|
+
(0, _dotenv.config)();
|
|
8
|
+
(0, _extendedTest.describe)("goToUrl E2E Tests", () => {
|
|
9
|
+
let browser;
|
|
10
|
+
let page;
|
|
11
|
+
(0, _extendedTest.beforeAll)(async () => {
|
|
12
|
+
browser = await _playwright.chromium.launch({
|
|
13
|
+
headless: true
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
(0, _extendedTest.afterAll)(async () => {
|
|
17
|
+
await browser.close();
|
|
18
|
+
});
|
|
19
|
+
(0, _extendedTest.beforeEach)(async () => {
|
|
20
|
+
page = await browser.newPage();
|
|
21
|
+
});
|
|
22
|
+
(0, _extendedTest.afterEach)(async () => {
|
|
23
|
+
await page.close();
|
|
24
|
+
});
|
|
25
|
+
(0, _extendedTest.describe)("ensureBrowserScripts", () => {
|
|
26
|
+
(0, _extendedTest.test)("should ensure browser scripts are loaded", async () => {
|
|
27
|
+
await (0, _ensureBrowserScripts.ensureBrowserScripts)(page);
|
|
28
|
+
(0, _extendedTest.expect)(await page.evaluate("typeof window.__INTUNED__")).toBe("object");
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
});
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.createXPathMapping = createXPathMapping;
|
|
7
|
+
exports.validateXPathMapping = validateXPathMapping;
|
|
8
|
+
var _ensureBrowserScripts = require("./ensureBrowserScripts");
|
|
9
|
+
async function validateXPathMapping(page, cachedMapping, prefix) {
|
|
10
|
+
try {
|
|
11
|
+
for (const [expectedText, entries] of Object.entries(cachedMapping)) {
|
|
12
|
+
for (const entry of entries) {
|
|
13
|
+
const {
|
|
14
|
+
xpath,
|
|
15
|
+
matchType
|
|
16
|
+
} = entry;
|
|
17
|
+
const elementExists = await page.evaluate(({
|
|
18
|
+
xpath,
|
|
19
|
+
prefix
|
|
20
|
+
}) => {
|
|
21
|
+
const element = document.evaluate(prefix ? `${prefix}/${xpath}` : xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
|
22
|
+
return element !== null;
|
|
23
|
+
}, {
|
|
24
|
+
xpath,
|
|
25
|
+
prefix
|
|
26
|
+
});
|
|
27
|
+
if (!elementExists) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
const actualText = await page.evaluate(({
|
|
31
|
+
xpath,
|
|
32
|
+
prefix,
|
|
33
|
+
matchType
|
|
34
|
+
}) => {
|
|
35
|
+
const element = document.evaluate(prefix ? `${prefix}/${xpath}` : xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
|
|
36
|
+
if (!element) return "";
|
|
37
|
+
if (matchType === "direct-text") {
|
|
38
|
+
let directText = "";
|
|
39
|
+
for (const child of element.childNodes) {
|
|
40
|
+
if (child.nodeType === Node.TEXT_NODE) {
|
|
41
|
+
directText += child.textContent || "";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return directText.trim();
|
|
45
|
+
} else if (matchType === "all-text") {
|
|
46
|
+
var _element$textContent;
|
|
47
|
+
return ((_element$textContent = element.textContent) === null || _element$textContent === void 0 ? void 0 : _element$textContent.trim()) || "";
|
|
48
|
+
} else if (typeof matchType === "object" && matchType.attribute) {
|
|
49
|
+
return element.getAttribute(matchType.attribute) || "";
|
|
50
|
+
}
|
|
51
|
+
return "";
|
|
52
|
+
}, {
|
|
53
|
+
xpath,
|
|
54
|
+
prefix,
|
|
55
|
+
matchType
|
|
56
|
+
});
|
|
57
|
+
if (actualText !== expectedText) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
} catch (error) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async function createXPathMapping(page, extractedData) {
|
|
68
|
+
const xpathMapping = {};
|
|
69
|
+
let uniqueValues = [];
|
|
70
|
+
await (0, _ensureBrowserScripts.ensureBrowserScripts)(page);
|
|
71
|
+
if (Array.isArray(extractedData)) {
|
|
72
|
+
if (extractedData.length > 0 && typeof extractedData[0] === "string") {
|
|
73
|
+
uniqueValues = [...new Set(extractedData)];
|
|
74
|
+
} else {
|
|
75
|
+
uniqueValues = [...new Set(extractedData.flatMap(obj => Object.values(obj)))];
|
|
76
|
+
}
|
|
77
|
+
} else if (extractedData && typeof extractedData === "object") {
|
|
78
|
+
uniqueValues = [...new Set(Object.values(extractedData).filter(value => value !== null))];
|
|
79
|
+
}
|
|
80
|
+
for (const value of uniqueValues) {
|
|
81
|
+
xpathMapping[value] = [];
|
|
82
|
+
const strategies = [{
|
|
83
|
+
locatorFn: () => page.getByText(value, {
|
|
84
|
+
exact: true
|
|
85
|
+
}),
|
|
86
|
+
matchType: "all-text"
|
|
87
|
+
}];
|
|
88
|
+
for (const strategy of strategies) {
|
|
89
|
+
const locators = strategy.locatorFn();
|
|
90
|
+
const count = await locators.count();
|
|
91
|
+
for (let i = 0; i < count; i++) {
|
|
92
|
+
const locator = locators.nth(i);
|
|
93
|
+
const xpath = await locator.evaluate(el => {
|
|
94
|
+
return window.__INTUNED__.getElementXPath(el);
|
|
95
|
+
});
|
|
96
|
+
const existingEntry = xpathMapping[value].find(entry => entry.xpath === xpath);
|
|
97
|
+
if (!existingEntry) {
|
|
98
|
+
xpathMapping[value].push({
|
|
99
|
+
xpath,
|
|
100
|
+
matchType: strategy.matchType
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return xpathMapping;
|
|
107
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.clickUntilExhausted = exports.clickButtonAndWait = void 0;
|
|
7
|
+
var _withNetworkSettledWait = require("./withNetworkSettledWait");
|
|
8
|
+
var _Logger = require("../common/Logger");
|
|
9
|
+
const getContainerState = async container => {
|
|
10
|
+
const count = await container.count();
|
|
11
|
+
if (count > 0) {
|
|
12
|
+
return await container.locator("> *").count();
|
|
13
|
+
}
|
|
14
|
+
return await container.evaluate(element => element.scrollHeight);
|
|
15
|
+
};
|
|
16
|
+
const clickButtonAndWaitInternal = async (page, buttonLocator, clickDelay) => {
|
|
17
|
+
await buttonLocator.scrollIntoViewIfNeeded();
|
|
18
|
+
await buttonLocator.click({
|
|
19
|
+
force: true
|
|
20
|
+
});
|
|
21
|
+
await new Promise(resolve => setTimeout(resolve, clickDelay * 1000));
|
|
22
|
+
};
|
|
23
|
+
const clickButtonAndWait = async input => {
|
|
24
|
+
const {
|
|
25
|
+
page,
|
|
26
|
+
buttonLocator,
|
|
27
|
+
clickDelay = 0.5
|
|
28
|
+
} = input;
|
|
29
|
+
await (0, _withNetworkSettledWait.withNetworkSettledWait)(async () => {
|
|
30
|
+
await clickButtonAndWaitInternal(page, buttonLocator, clickDelay);
|
|
31
|
+
}, {
|
|
32
|
+
page,
|
|
33
|
+
maxInflightRequests: 0,
|
|
34
|
+
timeoutInMs: 10000
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
exports.clickButtonAndWait = clickButtonAndWait;
|
|
38
|
+
const clickUntilExhausted = async input => {
|
|
39
|
+
const {
|
|
40
|
+
page,
|
|
41
|
+
buttonLocator,
|
|
42
|
+
heartbeat = undefined,
|
|
43
|
+
containerLocator = undefined,
|
|
44
|
+
maxClicks = 50,
|
|
45
|
+
clickDelay = 0.5,
|
|
46
|
+
noChangeThreshold = 0
|
|
47
|
+
} = input;
|
|
48
|
+
await (0, _withNetworkSettledWait.withNetworkSettledWait)(async () => {
|
|
49
|
+
let prevState = null;
|
|
50
|
+
if (containerLocator) {
|
|
51
|
+
prevState = await getContainerState(containerLocator);
|
|
52
|
+
_Logger.logger.info(`Initial container state: ${prevState}`);
|
|
53
|
+
}
|
|
54
|
+
const buttonCount = await buttonLocator.count();
|
|
55
|
+
_Logger.logger.info(`Button matches: ${buttonCount}`);
|
|
56
|
+
for (let i = 0; i < maxClicks; i++) {
|
|
57
|
+
heartbeat === null || heartbeat === void 0 || heartbeat();
|
|
58
|
+
const isVisible = await buttonLocator.isVisible();
|
|
59
|
+
if (!isVisible) {
|
|
60
|
+
_Logger.logger.info("Button not visible, stopping.");
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
const isEnabled = await buttonLocator.isEnabled();
|
|
64
|
+
if (!isEnabled) {
|
|
65
|
+
_Logger.logger.info("Button not enabled, stopping.");
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
await clickButtonAndWaitInternal(page, buttonLocator, clickDelay);
|
|
69
|
+
if (containerLocator) {
|
|
70
|
+
const currentState = await getContainerState(containerLocator);
|
|
71
|
+
_Logger.logger.info(`Current container state: ${currentState}`);
|
|
72
|
+
if (prevState !== null && currentState - prevState <= noChangeThreshold) {
|
|
73
|
+
_Logger.logger.info(`No significant change in container state: ${currentState} (previous: ${prevState})`);
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
prevState = currentState;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}, {
|
|
80
|
+
page,
|
|
81
|
+
maxInflightRequests: 0,
|
|
82
|
+
timeoutInMs: 30000
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
exports.clickUntilExhausted = clickUntilExhausted;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.downloadFile = void 0;
|
|
7
|
+
var _asyncMutex = require("async-mutex");
|
|
8
|
+
var _utils = require("./utils/");
|
|
9
|
+
var _resolveUrl = require("./resolveUrl");
|
|
10
|
+
const downloadMutex = new _asyncMutex.Mutex();
|
|
11
|
+
function isValidURL(string) {
|
|
12
|
+
try {
|
|
13
|
+
new URL(string);
|
|
14
|
+
return true;
|
|
15
|
+
} catch (_) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
async function getAbsoluteUrl(page, url) {
|
|
20
|
+
try {
|
|
21
|
+
const url_locator = page.locator(`a[href='${url}']`);
|
|
22
|
+
if ((await url_locator.count()) > 0) {
|
|
23
|
+
const href = await url_locator.evaluate(element => element.href);
|
|
24
|
+
return href;
|
|
25
|
+
}
|
|
26
|
+
} catch (error) {
|
|
27
|
+
console.error("Error getting absolute URL:", error);
|
|
28
|
+
}
|
|
29
|
+
const absUrl = await (0, _resolveUrl.resolveUrl)({
|
|
30
|
+
url,
|
|
31
|
+
page
|
|
32
|
+
});
|
|
33
|
+
return absUrl;
|
|
34
|
+
}
|
|
35
|
+
const downloadFile = async input => {
|
|
36
|
+
const {
|
|
37
|
+
page,
|
|
38
|
+
trigger,
|
|
39
|
+
timeoutInMs
|
|
40
|
+
} = input;
|
|
41
|
+
let pageToDownloadFrom = page;
|
|
42
|
+
let shouldClosePage = false;
|
|
43
|
+
let downloadPromise;
|
|
44
|
+
let isInvalidUrl = false;
|
|
45
|
+
const isUrlTrigger = trigger => {
|
|
46
|
+
return typeof trigger === "string";
|
|
47
|
+
};
|
|
48
|
+
const isCallableTrigger = trigger => {
|
|
49
|
+
return typeof trigger === "function";
|
|
50
|
+
};
|
|
51
|
+
const isLocatorTrigger = trigger => {
|
|
52
|
+
return typeof trigger === "object" && trigger !== null && "click" in trigger;
|
|
53
|
+
};
|
|
54
|
+
if (isUrlTrigger(trigger)) {
|
|
55
|
+
pageToDownloadFrom = await page.context().newPage();
|
|
56
|
+
shouldClosePage = true;
|
|
57
|
+
}
|
|
58
|
+
let action;
|
|
59
|
+
let absoluteUrl;
|
|
60
|
+
const release = await downloadMutex.acquire();
|
|
61
|
+
try {
|
|
62
|
+
downloadPromise = pageToDownloadFrom.waitForEvent("download", {
|
|
63
|
+
timeout: (timeoutInMs ?? 5000) + 1000
|
|
64
|
+
});
|
|
65
|
+
if (isUrlTrigger(trigger)) {
|
|
66
|
+
absoluteUrl = await getAbsoluteUrl(page, trigger);
|
|
67
|
+
if (!isValidURL(absoluteUrl)) {
|
|
68
|
+
isInvalidUrl = true;
|
|
69
|
+
console.warn(`Url is not valid, the download might not be triggered correctly. ${absoluteUrl}`);
|
|
70
|
+
}
|
|
71
|
+
try {
|
|
72
|
+
action = await pageToDownloadFrom.goto(absoluteUrl);
|
|
73
|
+
if (!action) {
|
|
74
|
+
throw new Error(`Failed to navigate to ${absoluteUrl}`);
|
|
75
|
+
}
|
|
76
|
+
const contentType = action.headers()["content-type"];
|
|
77
|
+
if (contentType && contentType.startsWith("image/")) {
|
|
78
|
+
await pageToDownloadFrom.evaluate(fullURL => {
|
|
79
|
+
const link = document.createElement("a");
|
|
80
|
+
link.href = fullURL;
|
|
81
|
+
link.download = "";
|
|
82
|
+
document.body.appendChild(link);
|
|
83
|
+
link.click();
|
|
84
|
+
document.body.removeChild(link);
|
|
85
|
+
}, absoluteUrl);
|
|
86
|
+
downloadPromise.catch(() => {
|
|
87
|
+
console.error(`Download was cancelled for URL: ${absoluteUrl}`);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
} catch (error) {
|
|
91
|
+
console.error("Error during download:", error);
|
|
92
|
+
}
|
|
93
|
+
} else if (isCallableTrigger(trigger)) {
|
|
94
|
+
action = await trigger(page);
|
|
95
|
+
} else if (isLocatorTrigger(trigger)) {
|
|
96
|
+
action = await trigger.click();
|
|
97
|
+
}
|
|
98
|
+
const download = await downloadPromise;
|
|
99
|
+
if ((0, _utils.isGenerateCodeMode)()) {
|
|
100
|
+
download.cancel();
|
|
101
|
+
}
|
|
102
|
+
return download;
|
|
103
|
+
} catch (error) {
|
|
104
|
+
if (isUrlTrigger(trigger) && !isInvalidUrl) {
|
|
105
|
+
const notFoundPatterns = ["404", "not found", "page not found", "page doesn't exist", "page does not exist", "resource not found"];
|
|
106
|
+
for (const pattern of notFoundPatterns) {
|
|
107
|
+
if ((await pageToDownloadFrom.getByText(pattern).count()) > 0) {
|
|
108
|
+
throw new Error(`Download timeout for url:${trigger}. Page appears to be a 404 page.`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
} else if (error instanceof Error && isLocatorTrigger(trigger)) {
|
|
112
|
+
throw new Error(`Failed to download file: ${error.message} Download was never triggered`);
|
|
113
|
+
} else if (error instanceof Error && isCallableTrigger(trigger)) {
|
|
114
|
+
throw new Error(`Failed to download file: ${error.message} Download was never triggered`);
|
|
115
|
+
} else if (isInvalidUrl) {
|
|
116
|
+
throw new Error(`Failed to download file: ${error.message} Url is not valid, the download did not trigger correctly.`);
|
|
117
|
+
}
|
|
118
|
+
} finally {
|
|
119
|
+
if (shouldClosePage) {
|
|
120
|
+
await pageToDownloadFrom.close();
|
|
121
|
+
}
|
|
122
|
+
release();
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
exports.downloadFile = downloadFile;
|