diff --git a/e2e/app/page/authenticated-page.ts b/e2e/app/page/authenticated-page.ts index b1cc7d53689..eda3eb777b9 100644 --- a/e2e/app/page/authenticated-page.ts +++ b/e2e/app/page/authenticated-page.ts @@ -3,11 +3,9 @@ import {PageUrl} from 'app/text-labels'; import BasePage from 'app/page/base-page'; import {getPropValue} from 'utils/element-utils'; import HelpTipsSidebar from 'app/component/help-tips-sidebar'; -import {savePageToFile, takeScreenshot} from 'utils/save-file-utils'; const signedInIndicator = 'app-signed-in'; - /** * AuthenticatedPage represents the base page for any AoU page after user has successfully logged in (aka authenticated). * This is the base page for all AoU pages to extends from. @@ -33,14 +31,8 @@ export default abstract class AuthenticatedPage extends BasePage { * Wait until current page is loaded and without spinners spinning. */ async waitForLoad(): Promise { - try { - await this.isSignedIn(); - await this.isLoaded(); - } catch (err) { - await savePageToFile(this.page); - await takeScreenshot(this.page); - throw (err); - } + await this.isSignedIn(); + await this.isLoaded(); await this.closeHelpSidebarIfOpen(); return this; } diff --git a/e2e/jest.config.js b/e2e/jest.config.js index 845f90ca80a..74e4c0beea6 100644 --- a/e2e/jest.config.js +++ b/e2e/jest.config.js @@ -3,7 +3,6 @@ const { TEST_MODE } = process.env; module.exports = { "verbose": false, - "bail": 1, // Stop running tests after `n` failures "preset": "jest-puppeteer", "testTimeout": 1200000, "testRunner": "jest-circus/runner", @@ -17,14 +16,25 @@ module.exports = { ], "reporters": [ "default", - "jest-junit", - [ - "jest-stare", { + ["jest-stare", { "resultDir": "logs", "resultJson": "test-results.json", "reportTitle": "AoU integration tests", "report": false } + ], + ["jest-junit", { + outputDirectory: "./logs/junit", + outputName: "test-results.xml", + classNameTemplate: "{filepath}", + suiteNameTemplate: "{filepath}", + suiteName: "AoU integration tests" + } + ], + ["/libs/jest-reporter.js", { + "outputdir": "logs/jest", + "filename": "test-results-summary.json" + } ] ], "transform": { diff --git a/e2e/jest.test-setup.ts b/e2e/jest.test-setup.ts index 6fc61017fcd..7e84d73be95 100644 --- a/e2e/jest.test-setup.ts +++ b/e2e/jest.test-setup.ts @@ -1,5 +1,6 @@ +import { logger } from 'libs/logger'; import * as fp from 'lodash/fp'; -import {Request} from 'puppeteer'; +import {JSHandle, Request} from 'puppeteer'; const userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'; /** @@ -17,14 +18,19 @@ beforeEach(async () => { page.setDefaultNavigationTimeout(60000); // Puppeteer default timeout is 30 seconds. await page.setRequestInterception(true); - const getTitle = async () => { + const getPageTitle = async () => { return await page.$eval('title', title => { return title.textContent; - }).catch(() => {return 'getTitle() func failed'}); + }).catch(() => {return 'getPageTitle() func failed'}); } - const describeJsHandle = async (jsHandle) => { + const describeJsHandle = async (jsHandle: JSHandle): Promise => { return jsHandle.executionContext().evaluate(obj => { + // Get error message if obj is an error. Error is not serializeable. + if (obj instanceof Error) { + return obj.message; + } + // Return JSON value of the argument or `undefined`. return obj.toString(); }, jsHandle); } @@ -70,18 +76,20 @@ beforeEach(async () => { : null; } - // Api response won't be logged. + // Disable logging of API response body in test log to make log less cluttered. + // Following API response body are not helpful for error troubleshooting. const shouldSkipApiResponseBody = (request: Request): boolean => { const filters = [ '/readonly', '/chartinfo/', - 'page-visits', + '/page-visits', '/generateCode/', '/criteria/CONDITION/search/', '/criteria/', '/cdrVersions', '/config', '/user-recent-workspaces', + '/user-recent-resources', '/profile' ]; return filters.some((partialUrl) => request && request.url().includes(partialUrl)); @@ -117,8 +125,8 @@ beforeEach(async () => { const response = request.response(); const failureText = request.failure() !== null ? stringifyData(request.failure().errorText) : ''; const responseText = stringifyData(await getResponseText(request)); - console.error('❗ Request failed: ' + - `${response.status()} ${request.method()} ${request.url()}\n${responseText}\n${failureText}`); + logger.log('error', 'Request failed: %s %s %s\n%s %s', + response.status(), request.method(), request.url(), responseText, failureText); } const transformResponseBody = async (request: Request): Promise => { @@ -128,7 +136,7 @@ beforeEach(async () => { // truncate long response. get first two workspace details. responseText = fp.isEmpty(JSON.parse(responseText).items) ? responseText - : 'truncated...\n' + JSON.stringify(JSON.parse(responseText).items.slice(0, 2), null, 2); + : `truncated...\n${JSON.stringify(JSON.parse(responseText).items.slice(0, 1), null, 2)}`; } return responseText; } @@ -141,8 +149,9 @@ beforeEach(async () => { // New request initiated page.on('request', (request) => { if (isWorkbenchRequest(request)) { - console.debug('❗ Request issued: ' + - `${request.method()} ${request.url()}\n${getRequestData(request)}`); + const requestBody = getRequestData(request); + const body = requestBody.length === 0 ? '' : `\n${requestBody}`; + logger.log('info', 'Request issued: %s %s %s', request.method(), request.url(), body); } try { request.continue(); @@ -166,17 +175,16 @@ beforeEach(async () => { if (isApiFailure(request)) { await logError(request); } else { - if (shouldSkipApiResponseBody(request)) { - console.debug(`❗ Request finished: ${status} ${method} ${url}`); - } else { - console.debug('❗ Request finished: ' + - `${status} ${method} ${url}\n${await transformResponseBody(request)}`); + let text = `Request finished: ${status} ${method} ${url}`; + if (!shouldSkipApiResponseBody(request)) { + text = `${text}\n${await transformResponseBody(request)}`; } + logger.log('info', text); } } } catch (err) { // Try find out what the request was - console.error(`${err}\n${status} ${method} ${url}`); + logger.log('error', '%s %s %s\n%s', status, method, url, err); } try { await request.continue(); @@ -186,33 +194,34 @@ beforeEach(async () => { }); page.on('console', async (message) => { - if (!message.args().length) { - return; - } - const title = await getTitle(); + if (!message.args().length) return; + const title = await getPageTitle(); try { const args = await Promise.all(message.args().map(a => describeJsHandle(a))); - console[message.type() === 'warning' ? 'warn' : message.type()](`❗ ${title}\n${message.text()}`, ...args); + console[message.type() === 'warning' ? 'warn' : message.type()](`Page console: "${title}"\n`, ...args); + console.log(''); } catch (err) { - console.error(`❗ ${title}\nException occurred when getting console message.\n${err}\n${message.text()}`); + console.error(`❗ "${title}"\nException occurred when getting page console message.\n${err}\n${message.text()}`); } }); page.on('error', async (error) => { - const title = await getTitle(); + const title = await getPageTitle(); try { - console.error(`❗ ${title}\nError message: ${error.message}\nStack: ${error.stack}`); + console.error(`PAGE ERROR: "${title}"\n${error.toString()}\n${error.message}\n${error.stack}`); + console.log(''); } catch (err) { - console.error(`❗ ${title}\nException occurred when getting error.\n${err}`); + console.error(`❗ "${title}"\nException occurred when getting page error.\n${err}`); } }); page.on('pageerror', async (error) => { - const title = await getTitle(); + const title = await getPageTitle(); try { - console.error(`❗ ${title}\nPage error message: ${error.message}\nStack: ${error.stack}`); + console.error(`PAGEERROR: "${title}"\n${error.toString()}\n${error.message}\n${error.stack}`); + console.log(''); } catch (err) { - console.error(`❗ ${title}\nPage exception occurred when getting pageerror.\n${err}`); + console.error(`❗ "${title}"\nPage exception occurred when getting pageerror.\n${err}`); } }) diff --git a/e2e/libs/jest-reporter.js b/e2e/libs/jest-reporter.js new file mode 100644 index 00000000000..63929822529 --- /dev/null +++ b/e2e/libs/jest-reporter.js @@ -0,0 +1,94 @@ +const fs = require('fs-extra'); +const path = require('path'); +const winston = require("winston"); + +module.exports = class JestReporter { + + constructor(globalConfig, options) { + if (globalConfig.verbose === true) { + throw Error("Verbose must be false or Console messages won't be available.") + } + this._globalConfig = globalConfig; + this._options = options; + this.logDir = this._options.outputdir || 'logs/jest'; + this.summaryFile = this._options.filename || 'test-results-summary.json'; + } + + onTestStart(test) { + const time = new Date().toLocaleTimeString(); + console.info(`Running ${path.parse(test.path).name} at ${time}`); + } + + // @ts-ignore + onTestResult(testRunConfig, testResult, runResults) { + const testName = path.parse(testResult.testFilePath).name; + let testLogName = `${this.logDir}/${testName}.log`; + testResult.testResults.forEach((result) => { + const status = result.status; + if (status === 'failed') { + testLogName = `${this.logDir}/${testName}-FAILED.log`; + } + }); + + const fileLogger = winston.createLogger({ + level: process.env.LOG_LEVEL || "info", + format: winston.format.combine( + winston.format.splat(), + winston.format.printf( (info) => {return `${info.message}`; }) + ), + transports: [new winston.transports.File({ + filename: testLogName, + options: { flags: 'w' }, + handleExceptions: true, + }) + ], + exitOnError: false + }); + + // Read jest console messages and save to a log file. + // Get all console logs. + if (testResult.console && testResult.console.length > 0) { + testResult.console.forEach((log) => { + fileLogger.info(log.message); + }); + } + + // Get failure messages. + testResult.testResults.forEach((result) => { + fileLogger.info('----------------------------------------'); + fileLogger.log('info', 'test name: %s', result.title); + fileLogger.log('info', 'status: %s', result.status); + // Get failure message. + if (result.failureMessages) { + const failure = result.failureMessages; + fileLogger.log('info', 'failure: %s', failure); + } + }); + console.log(`Save test log: ${testLogName}`); + } + + // @ts-ignore + onRunComplete(test, runResults) { + runResults.testResults.forEach(suite => { + const testFilePath = suite.testFilePath.split('e2e/')[1]; + const failedTests = []; + suite.testResults.forEach(result => { + if (result.status === 'failed') { + failedTests.push(`yarn test ${testFilePath}`); + } + }); + if (failedTests.length > 0) { + console.info(`**** To rerun failed tests:\n ${failedTests}`); + } + }); + + // Save test results to a file. + if (!fs.existsSync(this.logDir)) { + fs.mkdirSync(this.logDir); + } + fs.writeFileSync(`${this.logDir}/${this.summaryFile}`, JSON.stringify(runResults, null, 2)); + console.info(`Save tests results summary file: ${this.logDir}/${this.summaryFile}`); + return runResults; + } + +} diff --git a/e2e/libs/logger.js b/e2e/libs/logger.js new file mode 100644 index 00000000000..698305664f9 --- /dev/null +++ b/e2e/libs/logger.js @@ -0,0 +1,21 @@ +const winston = require('winston'); +const { createLogger, format } = winston; + +// Log to Console. +const logger = createLogger({ + level: process.env.LOG_LEVEL || "info", + format: format.combine( + format.prettyPrint(), + format.splat(), + format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }), + format.printf( (info) => { + return `${info.level.toUpperCase()}: [${info.timestamp}] - ${info.message}`; + }), + ), + transports: [ + new winston.transports.Console({ handleExceptions: true}), + ], + exitOnError: false +}); + +module.exports = { logger }; diff --git a/e2e/package.json b/e2e/package.json index 8fe822998c4..4cda59275b5 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -7,8 +7,8 @@ "license": "BSD", "scripts": { "impersonate-test-user": "env-cmd -x ../api/project.rb generate-impersonated-user-token --impersonated-user=\\$USER_NAME --output-token-filename=../e2e/puppeteer-access-token.txt", - "_test": "yarn impersonate-test-user && jest", - "_test:debugTest": "yarn impersonate-test-user && node --inspect-brk node_modules/.bin/jest", + "_test": "yarn impersonate-test-user && jest --no-color", + "_test:debugTest": "yarn impersonate-test-user && node --inspect-brk node_modules/.bin/jest --no-color", "test": "cross-env yarn _test --maxWorkers=5", "test:debugTest": "cross-env PUPPETEER_HEADLESS=false DEBUG=true yarn _test:debugTest", "test:debug": "cross-env PUPPETEER_HEADLESS=false DEBUG=true yarn _test --detectOpenHandles", @@ -18,7 +18,7 @@ "test-local-devup:debug": "cross-env WORKBENCH_ENV=local PUPPETEER_HEADLESS=false DEBUG=true node --inspect-brk node_modules/.bin/jest --maxWorkers=3", "test-staging": "cross-env WORKBENCH_ENV=staging yarn _test --maxWorkers=3", "test-staging:debug": "cross-env WORKBENCH_ENV=staging PUPPETEER_HEADLESS=false DEBUG=true yarn _test --maxWorkers=1", - "test:ci": "yarn _test --no-color --ci --maxWorkers=2 --forceExit", + "test:ci": "yarn _test --ci --maxWorkers=2 --forceExit", "test:ci:debug": "yarn _test --ci --debug --maxWorkers=1 --bail 1", "test-nightly": "cross-env TEST_MODE=nightly-integration yarn _test --maxWorkers=1", "test-nightly-local-devup": "cross-env TEST_MODE=nightly-integration yarn jest --maxWorkers=1", @@ -38,16 +38,11 @@ "engines": { "node": ">= 10.0.0" }, - "jest-junit": { - "outputDirectory": "./logs", - "outputName": "test-results.xml", - "classNameTemplate": "{filepath}", - "suiteNameTemplate": "{filepath}" - }, "dependencies": {}, "devDependencies": { "@types/expect-puppeteer": "4.4.5", "@types/faker": "5.1.5", + "@types/fs-extra": "^9.0.8", "@types/jest": "26.0.16", "@types/jest-environment-puppeteer": "4.4.0", "@types/lodash": "4.14.165", @@ -61,7 +56,7 @@ "jest": "26.6.3", "jest-circus": "26.6.3", "jest-config": "26.6.3", - "jest-junit": "^11.0.1", + "jest-junit": "^12.0.0", "jest-puppeteer": "4.4.0", "jest-stare": "2.2.0", "lodash": "4.17.20", @@ -74,6 +69,7 @@ "tslint-config-prettier": "1.18.0", "tslint-eslint-rules": "5.4.0", "tslint-microsoft-contrib": "6.2.0", - "typescript": "4.1.2" + "typescript": "4.1.2", + "winston": "^3.3.3" } } diff --git a/e2e/puppeteer-custom-environment.ts b/e2e/puppeteer-custom-environment.ts index 58ddc1b0821..442fffe1a15 100644 --- a/e2e/puppeteer-custom-environment.ts +++ b/e2e/puppeteer-custom-environment.ts @@ -4,6 +4,9 @@ require('jest-circus'); class PuppeteerCustomEnvironment extends PuppeteerEnvironment { + screenshotDir = `logs/screenshot`; + htmlDir = `logs/html`; + async setup() { await super.setup(); } @@ -26,6 +29,7 @@ class PuppeteerCustomEnvironment extends PuppeteerEnvironment { .slice(0, 15); } + // jest-circus: https://github.com/facebook/jest/blob/master/packages/jest-circus/README.md#overview // Take a screenshot right after failure async handleTestEvent(event, state) { switch (event.name) { @@ -34,28 +38,22 @@ class PuppeteerCustomEnvironment extends PuppeteerEnvironment { const runningTest = state.currentlyRunningTest; let testName; if (runningTest != null) { - testName = state.currentlyRunningTest.name.replace(/\W/g, '-'); + testName = runningTest.parent.name.replace(/\W/g, '-'); } else { testName = event.test.name.replace(/\W/g, '-'); } - const screenshotDir = `logs/screenshot`; - const htmlDir = `logs/html`; - await fs.ensureDir(screenshotDir); - await fs.ensureDir(htmlDir); - + await fs.ensureDir(this.screenshotDir); + await fs.ensureDir(this.htmlDir); const timestamp = this.localDateTimeString(); - - const screenshotFile = `${screenshotDir}/${testName}_${timestamp}.png`; + const screenshotFile = `${this.screenshotDir}/${testName}_${timestamp}.png`; await this.takeScreenshot(screenshotFile); - - const htmlFile = `${htmlDir}/${testName}_${timestamp}.html`; + const htmlFile = `${this.htmlDir}/${testName}_${timestamp}.html`; await this.savePageToFile(htmlFile); break; default: break; } - } async takeScreenshot(filePath) { diff --git a/e2e/yarn.lock b/e2e/yarn.lock index 7a5e1f60b87..e9ceb5f8916 100644 --- a/e2e/yarn.lock +++ b/e2e/yarn.lock @@ -279,6 +279,15 @@ exec-sh "^0.3.2" minimist "^1.2.0" +"@dabh/diagnostics@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.2.tgz#290d08f7b381b8f94607dc8f471a12c675f9db31" + integrity sha512-+A1YivoVDNNVCdfozHSR8v/jyuuLTMXwjWuxPFlFlUapXoGc+Gj9mDlTDDfrwl7rXCl2tNZ0kE8sIBO6YOn96Q== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + "@hapi/address@2.x.x": version "2.1.4" resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" @@ -643,6 +652,13 @@ resolved "https://registry.yarnpkg.com/@types/faker/-/faker-5.1.5.tgz#f14b015e0100232bb00c6dd7611505efb08709a0" integrity sha512-2uEQFb7bsx68rqD4F8q95wZq6LTLOyexjv6BnvJogCO4jStkyc6IDEkODPQcWfovI6g6M3uPQ2/uD/oedJKkNw== +"@types/fs-extra@^9.0.8": + version "9.0.8" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.8.tgz#32c3c07ddf8caa5020f84b5f65a48470519f78ba" + integrity sha512-bnlTVTwq03Na7DpWxFJ1dvnORob+Otb8xHyUqUWhqvz/Ksg8+JXPlR52oeMSZ37YEOa5PyccbgUNutiQdi13TA== + dependencies: + "@types/node" "*" + "@types/graceful-fs@^4.1.2": version "4.1.4" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.4.tgz#4ff9f641a7c6d1a3508ff88bc3141b152772e753" @@ -899,6 +915,11 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== +async@^3.1.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" + integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -1267,7 +1288,7 @@ collection-visit@^1.0.0: map-visit "^1.0.0" object-visit "^1.0.0" -color-convert@^1.9.0, color-convert@^1.9.3: +color-convert@^1.9.0, color-convert@^1.9.1, color-convert@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -1291,6 +1312,35 @@ color-name@^1.0.0, color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-string@^1.5.2: + version "1.5.4" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.4.tgz#dd51cd25cfee953d138fe4002372cc3d0e504cb6" + integrity sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@3.0.x: + version "3.0.0" + resolved "https://registry.yarnpkg.com/color/-/color-3.0.0.tgz#d920b4328d534a3ac8295d68f7bd4ba6c427be9a" + integrity sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w== + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" + +colors@^1.2.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + +colorspace@1.1.x: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.2.tgz#e0128950d082b86a2168580796a0aa5d6c68d8c5" + integrity sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ== + dependencies: + color "3.0.x" + text-hex "1.0.x" + combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" @@ -1345,7 +1395,7 @@ core-js@^2.6.5: resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== -core-util-is@1.0.2: +core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= @@ -1562,6 +1612,11 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -1781,6 +1836,11 @@ fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fast-safe-stringify@^2.0.4: + version "2.0.7" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" + integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== + fb-watchman@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" @@ -1795,6 +1855,11 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" +fecha@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.0.tgz#3ffb6395453e3f3efff850404f0a59b6747f5f41" + integrity sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg== + fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -1851,6 +1916,11 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + for-in@^0.1.3: version "0.1.8" resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" @@ -2170,7 +2240,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3, inherits@^2.0.4: +inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2204,6 +2274,11 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + is-buffer@^1.0.2, is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" @@ -2343,7 +2418,7 @@ isarray@0.0.1: resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= -isarray@1.0.0: +isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= @@ -2636,10 +2711,10 @@ jest-jasmine2@^26.6.3: pretty-format "^26.6.2" throat "^5.0.0" -jest-junit@^11.0.1: - version "11.1.0" - resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-11.1.0.tgz#79cd53948e44d62b2b30fa23ea0d7a899d2c8d7a" - integrity sha512-c2LFOyKY7+ZxL5zSu+WHmHfsJ2wqbOpeYJ4Uu26yMhFxny2J2NQj6AVS7M+Eaxji9Q/oIDDK5tQy0DGzDp9xOw== +jest-junit@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-12.0.0.tgz#3ebd4a6a84b50c4ab18323a8f7d9cceb9d845df6" + integrity sha512-+8K35LlboWiPuCnXSyiid7rFdxNlpCWWM20WEYe6IZH6psfUWKZmSpSRQ5tk0C0cBeDsvsnIzcef5mYhyJsbug== dependencies: mkdirp "^1.0.4" strip-ansi "^5.2.0" @@ -3096,6 +3171,11 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + lazy-cache@^0.2.3: version "0.2.7" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65" @@ -3154,6 +3234,17 @@ lodash@4.17.20, lodash@^4.17.19: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== +logform@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.2.0.tgz#40f036d19161fc76b68ab50fdc7fe495544492f2" + integrity sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg== + dependencies: + colors "^1.2.1" + fast-safe-stringify "^2.0.4" + fecha "^4.2.0" + ms "^2.1.1" + triple-beam "^1.3.0" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -3315,6 +3406,11 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + mustache@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.0.1.tgz#d99beb031701ad433338e7ea65e0489416c854a2" @@ -3468,6 +3564,13 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + onetime@^5.1.0: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" @@ -3644,6 +3747,11 @@ pretty-format@^26.0.0, pretty-format@^26.6.2: ansi-styles "^4.0.0" react-is "^17.0.1" +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + progress@^2.0.1: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" @@ -3727,6 +3835,19 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" +readable-stream@^2.3.7: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + readable-stream@^3.1.1, readable-stream@^3.4.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" @@ -3881,7 +4002,7 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-buffer@~5.1.1: +safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== @@ -4003,6 +4124,13 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" @@ -4145,6 +4273,11 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" + integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA= + stack-utils@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.4.tgz#4b600971dcfc6aed0cbdf2a8268177cc916c87c8" @@ -4204,6 +4337,13 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -4298,6 +4438,11 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + throat@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" @@ -4379,6 +4524,11 @@ tree-kill@^1.2.2: resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== +triple-beam@^1.2.0, triple-beam@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" + integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== + ts-jest@26.4.4: version "26.4.4" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.4.4.tgz#61f13fb21ab400853c532270e52cc0ed7e502c49" @@ -4588,7 +4738,7 @@ use@^3.1.0: resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -util-deprecate@^1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= @@ -4729,6 +4879,29 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" +winston-transport@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.4.0.tgz#17af518daa690d5b2ecccaa7acf7b20ca7925e59" + integrity sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw== + dependencies: + readable-stream "^2.3.7" + triple-beam "^1.2.0" + +winston@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/winston/-/winston-3.3.3.tgz#ae6172042cafb29786afa3d09c8ff833ab7c9170" + integrity sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw== + dependencies: + "@dabh/diagnostics" "^2.0.2" + async "^3.1.0" + is-stream "^2.0.0" + logform "^2.2.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.4.0" + word-wrap@~1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"