From 998fac9f461b3a373608e4b5b2acdda1095f19dd Mon Sep 17 00:00:00 2001 From: dangowans Date: Fri, 24 Sep 2021 14:27:28 -0400 Subject: [PATCH] custom errors, global browser refinements --- browser-global.d.ts | 3 ++- browser-global.js | 18 +++++++++++------- browser-global.ts | 21 +++++++++++++-------- config.d.ts | 2 ++ config.js | 2 ++ config.ts | 2 ++ index.js | 19 +++++++++++++++++-- index.ts | 23 +++++++++++++++++++++-- package-lock.json | 4 ++-- package.json | 2 +- 10 files changed, 73 insertions(+), 23 deletions(-) diff --git a/browser-global.d.ts b/browser-global.d.ts index 8133f9d..fb2b2dc 100644 --- a/browser-global.d.ts +++ b/browser-global.d.ts @@ -1,5 +1,6 @@ import puppeteer from "puppeteer"; export declare const setHeadless: (headlessStatus: boolean) => void; export declare const pageTimeoutMillis = 90000; -export declare const initializeBrowserGlobal: () => Promise; +export declare const getBrowserGlobal: () => Promise; +export declare const keepBrowserGlobalAlive: () => void; export declare const cleanUpBrowserGlobal: (useForce?: boolean) => Promise; diff --git a/browser-global.js b/browser-global.js index b68b922..af12ccb 100644 --- a/browser-global.js +++ b/browser-global.js @@ -7,34 +7,38 @@ export const setHeadless = (headlessStatus) => { }; export const pageTimeoutMillis = 90000; const browserStartupTimeoutMillis = 3 * 60000; -const browserGlobalExpiryMillis = browserStartupTimeoutMillis + (pageTimeoutMillis * 3); +const browserGlobalExpiryMillis = Math.max(browserStartupTimeoutMillis, pageTimeoutMillis) + 10000; let browserGlobal; let browserGlobalInitializedTime = 0; let browserGlobalTimer; -const isBrowserGlobalExpired = () => { - if (browserGlobalInitializedTime + browserGlobalExpiryMillis < Date.now()) { +const isBrowserGlobalReady = () => { + if (browserGlobal && browserGlobalInitializedTime + browserGlobalExpiryMillis > Date.now()) { return true; } return false; }; -export const initializeBrowserGlobal = async () => { - if (!browserGlobal || isBrowserGlobalExpired()) { +export const getBrowserGlobal = async () => { + if (!isBrowserGlobalReady()) { await cleanUpBrowserGlobal(); - browserGlobalInitializedTime = Date.now(); + keepBrowserGlobalAlive(); browserGlobal = await puppeteer.launch({ headless, timeout: browserStartupTimeoutMillis, args: ["--lang-en-CA,en"] }); + keepBrowserGlobalAlive(); browserGlobalTimer = setIntervalAsync(cleanUpBrowserGlobal, browserGlobalExpiryMillis); } return browserGlobal; }; +export const keepBrowserGlobalAlive = () => { + browserGlobalInitializedTime = Date.now(); +}; export const cleanUpBrowserGlobal = async (useForce = false) => { if (useForce) { browserGlobalInitializedTime = 0; } - if (browserGlobal && isBrowserGlobalExpired()) { + if (!isBrowserGlobalReady()) { try { await browserGlobal.close(); } diff --git a/browser-global.ts b/browser-global.ts index a0cea20..7def26a 100644 --- a/browser-global.ts +++ b/browser-global.ts @@ -21,28 +21,28 @@ export const setHeadless = (headlessStatus: boolean): void => { export const pageTimeoutMillis = 90_000; const browserStartupTimeoutMillis = 3 * 60_000; -const browserGlobalExpiryMillis = browserStartupTimeoutMillis + (pageTimeoutMillis * 3); +const browserGlobalExpiryMillis = Math.max(browserStartupTimeoutMillis, pageTimeoutMillis) + 10_000; let browserGlobal: puppeteer.Browser; let browserGlobalInitializedTime = 0; let browserGlobalTimer: SetIntervalAsyncTimer; -const isBrowserGlobalExpired = () => { +const isBrowserGlobalReady = () => { - if (browserGlobalInitializedTime + browserGlobalExpiryMillis < Date.now()) { + if (browserGlobal && browserGlobalInitializedTime + browserGlobalExpiryMillis > Date.now()) { return true; } return false; }; -export const initializeBrowserGlobal = async (): Promise => { +export const getBrowserGlobal = async (): Promise => { - if (!browserGlobal || isBrowserGlobalExpired()) { + if (!isBrowserGlobalReady()) { await cleanUpBrowserGlobal(); - browserGlobalInitializedTime = Date.now(); + keepBrowserGlobalAlive(); browserGlobal = await puppeteer.launch({ headless, @@ -50,6 +50,7 @@ export const initializeBrowserGlobal = async (): Promise => { args: ["--lang-en-CA,en"] }); + keepBrowserGlobalAlive(); browserGlobalTimer = setIntervalAsync(cleanUpBrowserGlobal, browserGlobalExpiryMillis); } @@ -57,13 +58,17 @@ export const initializeBrowserGlobal = async (): Promise => { return browserGlobal; }; +export const keepBrowserGlobalAlive = (): void => { + browserGlobalInitializedTime = Date.now(); +}; + export const cleanUpBrowserGlobal = async (useForce = false): Promise => { if (useForce) { browserGlobalInitializedTime = 0; } - if (browserGlobal && isBrowserGlobalExpired()) { + if (!isBrowserGlobalReady()) { try { await browserGlobal.close(); @@ -79,7 +84,7 @@ export const cleanUpBrowserGlobal = async (useForce = false): Promise => { } catch { // ignore } - + browserGlobalTimer = undefined; } diff --git a/config.d.ts b/config.d.ts index d8dd20b..bce86eb 100644 --- a/config.d.ts +++ b/config.d.ts @@ -2,6 +2,8 @@ export declare const clearanceStart_url = "https://onlineservices.wsib.on.ca/Cle export declare const clearanceStart_searchFormSelector = "#TOKENSimpleSearchForm"; export declare const clearanceStart_searchFieldSelector = "#simpleAccountNumbersTOKEN"; export declare const clearanceResult_certificateLinkSelector = "#eClearanceWorkspaceTargSubDivFormXX .fancytable a[rel='eClearanceWorkspaceContent'][href^='GCSearchCertDet']"; +export declare const clearanceResult_certificateBadStandingSelector = "#eClearanceWorkspaceTargSubDivFormXX .fancytable .badstanding"; +export declare const clearanceResult_defaultErrorMessage = "Clearance certificate link not found."; export declare const certificate_tableSelector = "#eClearanceWorkspaceDivForm .fancytable"; export declare const certificateField_contractorLegalTradeName = "Contractor Legal / Trade Name"; export declare const certificateField_contractorAddress = "Contractor Address"; diff --git a/config.js b/config.js index 915df9c..8fb687b 100644 --- a/config.js +++ b/config.js @@ -2,6 +2,8 @@ export const clearanceStart_url = "https://onlineservices.wsib.on.ca/Clearances/ export const clearanceStart_searchFormSelector = "#TOKENSimpleSearchForm"; export const clearanceStart_searchFieldSelector = "#simpleAccountNumbersTOKEN"; export const clearanceResult_certificateLinkSelector = "#eClearanceWorkspaceTargSubDivFormXX .fancytable a[rel='eClearanceWorkspaceContent'][href^='GCSearchCertDet']"; +export const clearanceResult_certificateBadStandingSelector = "#eClearanceWorkspaceTargSubDivFormXX .fancytable .badstanding"; +export const clearanceResult_defaultErrorMessage = "Clearance certificate link not found."; export const certificate_tableSelector = "#eClearanceWorkspaceDivForm .fancytable"; export const certificateField_contractorLegalTradeName = "Contractor Legal / Trade Name"; export const certificateField_contractorAddress = "Contractor Address"; diff --git a/config.ts b/config.ts index 8c96adb..7a1ed20 100644 --- a/config.ts +++ b/config.ts @@ -8,6 +8,8 @@ export const clearanceStart_searchFieldSelector = "#simpleAccountNumbersTOKEN"; // Search Results export const clearanceResult_certificateLinkSelector = "#eClearanceWorkspaceTargSubDivFormXX .fancytable a[rel='eClearanceWorkspaceContent'][href^='GCSearchCertDet']"; +export const clearanceResult_certificateBadStandingSelector = "#eClearanceWorkspaceTargSubDivFormXX .fancytable .badstanding"; +export const clearanceResult_defaultErrorMessage = "Clearance certificate link not found."; // Certificate diff --git a/index.js b/index.js index 1df1a41..9b79b90 100644 --- a/index.js +++ b/index.js @@ -27,7 +27,7 @@ const cleanRawCertificateOutput = (rawOutput) => { export const getClearanceByAccountNumber = async (accountNumber) => { let page; try { - const browser = await browserGlobal.initializeBrowserGlobal(); + const browser = await browserGlobal.getBrowserGlobal(); page = await browser.newPage(); page.setDefaultNavigationTimeout(browserGlobal.pageTimeoutMillis); page.setDefaultTimeout(browserGlobal.pageTimeoutMillis); @@ -41,6 +41,7 @@ export const getClearanceByAccountNumber = async (accountNumber) => { if (!pageResponse.ok) { throw new Error("Response Code = " + pageResponse.status().toString()); } + browserGlobal.keepBrowserGlobalAlive(); await page.waitForSelector("body"); await page.$eval(config.clearanceStart_searchFieldSelector, (inputEle, accountNumber_value) => { inputEle.value = accountNumber_value; @@ -48,13 +49,27 @@ export const getClearanceByAccountNumber = async (accountNumber) => { await page.$eval(config.clearanceStart_searchFormSelector, (formEle) => { formEle.submit(); }); + browserGlobal.keepBrowserGlobalAlive(); await page.waitForSelector("body"); + let hasError = false; await page.$eval(config.clearanceResult_certificateLinkSelector, (linkEle) => { linkEle.click(); }) .catch(() => { - throw new Error("Clearance certificate link not found."); + hasError = true; }); + if (hasError) { + const errorMessage = await page.$eval(config.clearanceResult_certificateBadStandingSelector, (badStandingEle) => { + return badStandingEle + ? badStandingEle.textContent + : config.clearanceResult_defaultErrorMessage; + }) + .catch(() => { + throw new Error(config.clearanceResult_defaultErrorMessage); + }); + throw new Error(errorMessage); + } + browserGlobal.keepBrowserGlobalAlive(); await page.waitForSelector("body"); const certificateURL = page.url(); const parsedTable = await page.$eval(config.certificate_tableSelector, (tableEle) => { diff --git a/index.ts b/index.ts index 47d7642..43be4fd 100644 --- a/index.ts +++ b/index.ts @@ -46,7 +46,7 @@ export const getClearanceByAccountNumber = async (accountNumber: string): Promis let page: puppeteer.Page; try { - const browser = await browserGlobal.initializeBrowserGlobal(); + const browser = await browserGlobal.getBrowserGlobal(); page = await browser.newPage(); @@ -70,6 +70,7 @@ export const getClearanceByAccountNumber = async (accountNumber: string): Promis throw new Error("Response Code = " + pageResponse.status().toString()); } + browserGlobal.keepBrowserGlobalAlive(); await page.waitForSelector("body"); // Fill out form @@ -82,17 +83,35 @@ export const getClearanceByAccountNumber = async (accountNumber: string): Promis formEle.submit(); }); + browserGlobal.keepBrowserGlobalAlive(); await page.waitForSelector("body"); // Find result link + let hasError = false; + await page.$eval(config.clearanceResult_certificateLinkSelector, (linkEle: HTMLAnchorElement) => { linkEle.click(); }) .catch(() => { - throw new Error("Clearance certificate link not found."); + hasError = true; }); + if (hasError) { + + const errorMessage = await page.$eval(config.clearanceResult_certificateBadStandingSelector, (badStandingEle: HTMLElement) => { + return badStandingEle + ? badStandingEle.textContent + : config.clearanceResult_defaultErrorMessage; + }) + .catch(() => { + throw new Error(config.clearanceResult_defaultErrorMessage); + }); + + throw new Error(errorMessage); + } + + browserGlobal.keepBrowserGlobalAlive(); await page.waitForSelector("body"); // Parse the certificate diff --git a/package-lock.json b/package-lock.json index 3becb03..4cc0add 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@cityssm/wsib-clearance-check", - "version": "3.0.0-beta", + "version": "3.0.0-beta.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@cityssm/wsib-clearance-check", - "version": "3.0.0-beta", + "version": "3.0.0-beta.1", "license": "MIT", "dependencies": { "exit-hook": "^3.0.0", diff --git a/package.json b/package.json index bc4131e..dc9d350 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cityssm/wsib-clearance-check", - "version": "3.0.0-beta", + "version": "3.0.0-beta.1", "description": "A tool to scrape the clearance certificate status from the WSIB Online Services website.", "keywords": [ "wsib",