diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 249de28d6..bef012256 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -31,7 +31,7 @@ jobs: - name: Setup node.js uses: actions/setup-node@v2 with: - node-version: '16.5.0' + node-version: '16.9.1' - name: Install global dependencies run: npm install -g yarn@1.22.10 typescript@4.4.2 ts-node@10.2.1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f8bd9af4d..44a1bc05b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '16.5.0' + node-version: '16.9.1' - run: npm install -g yarn@1.22.10 - name: Cache Desktop node_modules @@ -43,7 +43,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '16.5.0' + node-version: '16.9.1' - run: npm install -g yarn@1.22.10 - name: Cache Desktop node_modules @@ -63,7 +63,7 @@ jobs: run: yarn electron:install-app-deps - run: yarn test-node - run: yarn test-electron - - run: yarn grunt test-release:osx + - run: yarn test-release env: NODE_ENV: production @@ -77,7 +77,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '16.5.0' + node-version: '16.9.1' - run: sudo apt-get install xvfb - run: npm install -g yarn@1.22.10 @@ -99,7 +99,7 @@ jobs: env: LANG: en_US LANGUAGE: en_US - - run: xvfb-run --auto-servernum yarn grunt test-release:linux + - run: xvfb-run --auto-servernum yarn test-release env: NODE_ENV: production @@ -114,7 +114,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 with: - node-version: '16.5.0' + node-version: '16.9.1' - run: npm install -g yarn@1.22.10 - name: Cache Desktop node_modules @@ -135,7 +135,7 @@ jobs: - run: type temp.json | findstr /v certificateSubjectName | findstr /v certificateSha1 > package.json - run: yarn prepare-beta-build - run: yarn build - - run: node build\grunt.js test - - run: node build\grunt.js test-release:win + - run: yarn test-electron + - run: yarn test-release env: SIGNAL_ENV: production diff --git a/.gitignore b/.gitignore index 0b7a35ae9..4388c1a0a 100644 --- a/.gitignore +++ b/.gitignore @@ -21,9 +21,7 @@ tsconfig.tsbuildinfo js/components.js js/util_worker.js libtextsecure/components.js -libtextsecure/test/test.js stylesheets/*.css -test/test.js /storybook-static/ preload.bundle.* ts/sql/mainWorker.bundle.js.LICENSE.txt diff --git a/.nvmrc b/.nvmrc index 28ebe8b4d..06e751596 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -16.5.0 +16.9.1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 62352e3cd..0746e38f1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -281,7 +281,7 @@ yarn generate yarn build ``` -Then, run the tests using `grunt test-release:osx --dir=release`, replacing `osx` with `linux` or `win` depending on your platform. +Then, run the tests using `yarn test-release`. ## Translations diff --git a/Gruntfile.js b/Gruntfile.js index 95d620457..be50217cc 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,36 +1,14 @@ // Copyright 2014-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -const { join } = require('path'); const importOnce = require('node-sass-import-once'); const rimraf = require('rimraf'); const mkdirp = require('mkdirp'); -const spectron = require('spectron'); -const asar = require('asar'); -const fs = require('fs'); -const os = require('os'); -const assert = require('assert'); const sass = require('node-sass'); -const packageJson = require('./package.json'); /* eslint-disable more/no-then, no-console */ module.exports = grunt => { - async function promiseToAsyncGruntTask(promise, gruntDone) { - let succeeded = false; - try { - await promise; - succeeded = true; - } catch (err) { - grunt.log.error(err); - } - if (succeeded) { - gruntDone(); - } else { - gruntDone(false); - } - } - const bower = grunt.file.readJSON('bower.json'); const components = []; // eslint-disable-next-line guard-for-in, no-restricted-syntax @@ -47,23 +25,6 @@ module.exports = grunt => { src: components, dest: 'js/components.js', }, - test: { - src: [ - 'node_modules/mocha/mocha.js', - 'node_modules/chai/chai.js', - 'test/_test.js', - ], - dest: 'test/test.js', - }, - libtextsecuretest: { - src: [ - 'node_modules/jquery/dist/jquery.js', - 'node_modules/mocha/mocha.js', - 'node_modules/chai/chai.js', - 'libtextsecure/test/_test.js', - ], - dest: 'libtextsecure/test/test.js', - }, }, sass: { options: { @@ -116,24 +77,6 @@ module.exports = grunt => { cmd: 'yarn build-protobuf', }, }, - 'test-release': { - osx: { - archive: `mac/${packageJson.productName}.app/Contents/Resources/app.asar`, - exe: `mac/${packageJson.productName}.app/Contents/MacOS/${packageJson.productName}`, - }, - mas: { - archive: 'mas/Signal.app/Contents/Resources/app.asar', - exe: `mas/${packageJson.productName}.app/Contents/MacOS/${packageJson.productName}`, - }, - linux: { - archive: 'linux-unpacked/resources/app.asar', - exe: `linux-unpacked/${packageJson.name}`, - }, - win: { - archive: 'win-unpacked/resources/app.asar', - exe: `win-unpacked/${packageJson.productName}.exe`, - }, - }, gitinfo: {}, // to be populated by grunt gitinfo }); @@ -187,238 +130,12 @@ module.exports = grunt => { mkdirp.sync('release'); }); - async function runTests(environment) { - const { Application } = spectron; - const electronBinary = - process.platform === 'win32' ? 'electron.cmd' : 'electron'; - - const path = join(__dirname, 'node_modules', '.bin', electronBinary); - const args = [join(__dirname, 'app', 'main.js')]; - grunt.log.writeln('Starting path', path, 'with args', args); - const app = new Application({ - path, - args, - env: { - NODE_ENV: environment, - }, - requireName: 'unused', - startTimeout: 30000, - }); - - function getMochaResults() { - // eslint-disable-next-line no-undef - return window.mochaResults; - } - - async function logForFailure() { - const temporaryDirectory = join( - os.tmpdir(), - `Signal-Desktop-tests--${Date.now()}-${Math.random() - .toString() - .slice(2)}` - ); - const renderProcessLogPath = join( - temporaryDirectory, - 'render-process.log' - ); - const mainProcessLogPath = join(temporaryDirectory, 'main-process.log'); - - await fs.promises.mkdir(temporaryDirectory, { recursive: true }); - - await Promise.all([ - (async () => { - const logs = await app.client.getRenderProcessLogs(); - await fs.promises.writeFile( - renderProcessLogPath, - logs.map(log => JSON.stringify(log)).join('\n') - ); - })(), - (async () => { - const logs = await app.client.getMainProcessLogs(); - await fs.promises.writeFile(mainProcessLogPath, logs.join('\n')); - })(), - ]); - - console.error(); - grunt.log.error( - `Renderer process logs written to ${renderProcessLogPath}` - ); - grunt.log.error(`Renderer process logs written to ${mainProcessLogPath}`); - grunt.log.error( - `For easier debugging, try NODE_ENV='${environment}' yarn start` - ); - console.error(); - } - - try { - await app.start(); - - grunt.log.writeln('App started. Now waiting for test results...'); - await app.client.waitUntil( - () => - app.client.execute(getMochaResults).then(data => Boolean(data.value)), - 25000, - 'Expected to find window.mochaResults set!' - ); - - const results = (await app.client.execute(getMochaResults)).value; - if (!results) { - await logForFailure(); - throw new Error("Couldn't extract test results"); - } - - if (results.failures > 0) { - const errorMessage = `Found ${results.failures} failing test${ - results.failures === 1 ? '' : 's' - }.`; - grunt.log.error(errorMessage); - results.reports.forEach(report => { - grunt.log.error(JSON.stringify(report, null, 2)); - }); - await logForFailure(); - throw new Error(errorMessage); - } - - grunt.log.ok(`${results.passes} tests passed.`); - } finally { - if (app.isRunning()) { - await app.stop(); - } - } - } - - grunt.registerTask( - 'unit-tests', - 'Run unit tests w/Electron', - function thisNeeded() { - const environment = grunt.option('env') || 'test'; - promiseToAsyncGruntTask(runTests(environment), this.async()); - } - ); - - grunt.registerTask( - 'lib-unit-tests', - 'Run libtextsecure unit tests w/Electron', - function thisNeeded() { - const environment = grunt.option('env') || 'test-lib'; - promiseToAsyncGruntTask(runTests(environment), this.async()); - } - ); - - grunt.registerMultiTask( - 'test-release', - 'Test packaged releases', - function thisNeeded() { - const dir = grunt.option('dir') || 'release'; - const environment = grunt.option('env') || 'production'; - const config = this.data; - const archive = [dir, config.archive].join('/'); - const files = [ - 'config/default.json', - `config/${environment}.json`, - `config/local-${environment}.json`, - ]; - - console.log(this.target, archive); - const releaseFiles = files.concat(config.files || []); - releaseFiles.forEach(fileName => { - console.log(fileName); - try { - asar.statFile(archive, fileName); - return true; - } catch (e) { - console.log(e); - throw new Error(`Missing file ${fileName}`); - } - }); - - if (config.appUpdateYML) { - const appUpdateYML = [dir, config.appUpdateYML].join('/'); - if (fs.existsSync(appUpdateYML)) { - console.log('auto update ok'); - } else { - throw new Error(`Missing auto update config ${appUpdateYML}`); - } - } - - const done = this.async(); - // A simple test to verify a visible window is opened with a title - const { Application } = spectron; - - const path = [dir, config.exe].join('/'); - console.log('Starting path', path); - const app = new Application({ - path, - }); - - const sleep = millis => - new Promise(resolve => setTimeout(resolve, millis)); - - Promise.race([app.start(), sleep(15000)]) - .then(() => { - if (!app.isRunning()) { - throw new Error('Application failed to start'); - } - - return app.client.getWindowCount(); - }) - .then(count => { - assert.equal(count, 1); - console.log('window opened'); - }) - .then(() => - // Verify the window's title - app.client.waitUntil( - async () => - (await app.client.getTitle()) === packageJson.productName, - { - timeoutMsg: `Expected window title to be ${JSON.stringify( - packageJson.productName - )}`, - } - ) - ) - .then(() => { - console.log('title ok'); - }) - .then(() => { - assert( - app.chromeDriver.logLines.indexOf(`NODE_ENV ${environment}`) > -1 - ); - console.log('environment ok'); - }) - .then( - () => - // Successfully completed test - app.stop(), - error => - // Test failed! - app.stop().then(() => { - grunt.fail.fatal(`Test failed: ${error.message} ${error.stack}`); - }) - ) - .catch(error => { - console.log('Main process logs:'); - app.client.getMainProcessLogs().then(logs => { - logs.forEach(log => { - console.log(log); - }); - - // Test failed! - grunt.fail.fatal(`Failure! ${error.message} ${error.stack}`); - }); - }) - .then(done); - } - ); - grunt.registerTask('tx', [ 'exec:tx-pull-mostly-translated', 'exec:tx-pull-any-existing-translation', 'locale-patch', ]); grunt.registerTask('dev', ['default', 'watch']); - grunt.registerTask('test', ['unit-tests', 'lib-unit-tests']); grunt.registerTask('date', ['gitinfo', 'getExpireTime']); grunt.registerTask('default', [ 'exec:build-protobuf', diff --git a/app/main.ts b/app/main.ts index aa05d7584..d0e415bbd 100644 --- a/app/main.ts +++ b/app/main.ts @@ -23,6 +23,7 @@ import { screen, shell, systemPreferences, + desktopCapturer, } from 'electron'; import { z } from 'zod'; @@ -587,11 +588,10 @@ async function createWindow() { if (getEnvironment() === Environment.Test) { mainWindow.loadURL( - prepareFileUrl([__dirname, '../test/index.html'], moreKeys) - ); - } else if (getEnvironment() === Environment.TestLib) { - mainWindow.loadURL( - prepareFileUrl([__dirname, '../libtextsecure/test/index.html'], moreKeys) + prepareFileUrl([__dirname, '../test/index.html'], { + ...moreKeys, + argv: JSON.stringify(process.argv), + }) ); } else { mainWindow.loadURL( @@ -1424,10 +1424,7 @@ app.on('ready', async () => { addSensitivePath(userDataPath); - if ( - getEnvironment() !== Environment.Test && - getEnvironment() !== Environment.TestLib - ) { + if (getEnvironment() !== Environment.Test) { installFileHandler({ protocol: electronProtocol, userDataPath, @@ -2120,3 +2117,20 @@ ipc.handle('show-save-dialog', async (_event, { defaultPath }) => { defaultPath, }); }); + +ipc.handle('getScreenCaptureSources', async () => { + return desktopCapturer.getSources({ + fetchWindowIcons: true, + thumbnailSize: { height: 102, width: 184 }, + types: ['window', 'screen'], + }); +}); + +if (isTestEnvironment(getEnvironment())) { + ipc.handle('ci:test-electron:done', async (_event, info) => { + process.stdout.write( + `ci:test-electron:done=${JSON.stringify(info)}\n`, + () => app.quit() + ); + }); +} diff --git a/app/user_config.ts b/app/user_config.ts index b1ffddd8a..8b8f5124c 100644 --- a/app/user_config.ts +++ b/app/user_config.ts @@ -2,19 +2,29 @@ // SPDX-License-Identifier: AGPL-3.0-only import { join } from 'path'; +import { mkdirSync } from 'fs'; import { app } from 'electron'; import { start } from './base_config'; import config from './config'; +let userData: string | undefined; // Use separate data directory for benchmarks & development if (config.has('storagePath')) { - app.setPath('userData', String(config.get('storagePath'))); + userData = String(config.get('storagePath')); } else if (config.has('storageProfile')) { - const userData = join( + userData = join( app.getPath('appData'), `Signal-${config.get('storageProfile')}` ); +} + +if (userData !== undefined) { + try { + mkdirSync(userData, { recursive: true }); + } catch (error) { + console.error('Failed to create userData', error?.stack || String(error)); + } app.setPath('userData', userData); } diff --git a/libtextsecure/test/.eslintrc.js b/libtextsecure/test/.eslintrc.js deleted file mode 100644 index de9f8080f..000000000 --- a/libtextsecure/test/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2020 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -module.exports = { - env: { - browser: true, - node: false, - mocha: true, - }, - parserOptions: { - sourceType: 'script', - }, - rules: { - strict: 'off', - 'more/no-then': 'off', - }, - globals: { - assert: true, - getString: true, - }, -}; diff --git a/libtextsecure/test/_test.js b/libtextsecure/test/_test.js deleted file mode 100644 index 4952266f8..000000000 --- a/libtextsecure/test/_test.js +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2015-2020 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -/* global chai */ - -mocha.setup('bdd'); -window.assert = chai.assert; - -const OriginalReporter = mocha._reporter; - -const SauceReporter = function Constructor(runner) { - const failedTests = []; - - runner.on('end', () => { - window.mochaResults = runner.stats; - window.mochaResults.reports = failedTests; - }); - - runner.on('fail', (test, err) => { - const flattenTitles = item => { - const titles = []; - while (item.parent.title) { - titles.push(item.parent.title); - // eslint-disable-next-line no-param-reassign - item = item.parent; - } - return titles.reverse(); - }; - failedTests.push({ - name: test.title, - result: false, - message: err.message, - stack: err.stack, - titles: flattenTitles(test), - }); - }); - - // eslint-disable-next-line no-new - new OriginalReporter(runner); -}; - -SauceReporter.prototype = OriginalReporter.prototype; - -mocha.reporter(SauceReporter); - -/* - * global helpers for tests - */ - -window.Whisper = window.Whisper || {}; -window.Whisper.events = { - on() {}, - trigger() {}, -}; - -before(async () => { - try { - window.SignalContext.log.info('Initializing SQL in renderer'); - const isTesting = true; - await window.Signal.Data.startInRenderer(isTesting); - window.SignalContext.log.info('SQL initialized in renderer'); - } catch (err) { - window.SignalContext.log.error( - 'SQL failed to initialize', - err && err.stack ? err.stack : err - ); - } - - await window.Signal.Util.initializeMessageCounter(); -}); diff --git a/libtextsecure/test/fake_web_api.js b/libtextsecure/test/fake_web_api.js deleted file mode 100644 index 5bb4da454..000000000 --- a/libtextsecure/test/fake_web_api.js +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2018-2020 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -window.setImmediate = window.nodeSetImmediate; - -const getKeysForIdentifierMap = {}; -const messagesSentMap = {}; - -const fakeCall = () => Promise.resolve(); - -const fakeAPI = { - confirmCode: fakeCall, - getAttachment: fakeCall, - getAvatar: fakeCall, - getDevices: fakeCall, - // getKeysForIdentifier : fakeCall, - getMyKeys: fakeCall, - getProfile: fakeCall, - getProvisioningResource: fakeCall, - putAttachment: fakeCall, - registerKeys: fakeCall, - requestVerificationSMS: fakeCall, - requestVerificationVoice: fakeCall, - // sendMessages: fakeCall, - setSignedPreKey: fakeCall, - - getKeysForIdentifier(number) { - const res = getKeysForIdentifierMap[number]; - if (res !== undefined) { - delete getKeysForIdentifierMap[number]; - return Promise.resolve(res); - } - throw new Error('getKeysForIdentfier of unknown/used number'); - }, - - sendMessages(destination, messageArray) { - for (let i = 0, max = messageArray.length; i < max; i += 1) { - const msg = messageArray[i]; - if ( - (msg.type !== 1 && msg.type !== 3) || - msg.destinationDeviceId === undefined || - msg.destinationRegistrationId === undefined || - msg.body === undefined || - msg.timestamp === undefined || - msg.relay !== undefined || - msg.destination !== undefined - ) { - throw new Error('Invalid message'); - } - - messagesSentMap[`${destination}.${messageArray[i].destinationDeviceId}`] = - msg; - } - }, -}; - -window.WebAPI = { - connect: () => fakeAPI, -}; diff --git a/libtextsecure/test/index.html b/libtextsecure/test/index.html deleted file mode 100644 index e4b831ce4..000000000 --- a/libtextsecure/test/index.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - libtextsecure test runner - - - -
-
- - - - - - - - - - - - - - - - - - diff --git a/package.json b/package.json index cfa86662c..f95be61db 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "prepare-windows-cert": "node scripts/prepare_windows_cert.js", "publish-to-apt": "NAME=$npm_package_name VERSION=$npm_package_version ./aptly.sh", "test": "yarn test-node && yarn test-electron", - "test-electron": "yarn grunt test", + "test-electron": "node ts/build/test-electron.js", + "test-release": "node ts/build/test-release.js", "test-node": "electron-mocha --file test/setup-test-node.js --recursive test/app test/modules ts/test-node ts/test-both", "test-node-coverage": "nyc --reporter=lcov --reporter=text mocha --recursive test/app test/modules ts/test-node ts/test-both", "eslint": "eslint --cache .", @@ -207,7 +208,7 @@ "@types/lru-cache": "5.1.0", "@types/memoizee": "0.4.2", "@types/mkdirp": "0.5.2", - "@types/mocha": "5.0.0", + "@types/mocha": "9.0.0", "@types/mustache": "4.1.2", "@types/node": "14.14.37", "@types/node-fetch": "2.5.7", @@ -238,6 +239,7 @@ "@types/uuid": "3.4.4", "@types/webpack-dev-server": "3.11.3", "@types/websocket": "1.0.0", + "@types/yargs": "17.0.7", "@typescript-eslint/eslint-plugin": "4.30.0", "@typescript-eslint/parser": "4.30.0", "arraybuffer-loader": "1.0.3", @@ -250,9 +252,9 @@ "core-js": "2.6.9", "cross-env": "5.2.0", "css-loader": "3.2.0", - "electron": "15.3.2", + "electron": "16.0.4", "electron-builder": "22.14.5", - "electron-mocha": "10.1.0", + "electron-mocha": "11.0.2", "electron-notarize": "0.1.1", "eslint": "7.7.0", "eslint-config-airbnb-typescript-prettier": "3.1.0", @@ -271,7 +273,7 @@ "grunt-gitinfo": "0.1.9", "grunt-sass": "3.1.0", "html-webpack-plugin": "5.3.1", - "mocha": "4.1.0", + "mocha": "9.1.3", "mocha-testcheck": "1.0.0-rc.0", "node-gyp": "7.1.2", "node-sass": "6.0.1", @@ -279,11 +281,11 @@ "npm-run-all": "4.1.5", "nyc": "11.4.1", "patch-package": "6.4.7", + "playwright": "1.17.1", "prettier": "2.4.1", "react-docgen-typescript": "1.2.6", "sass-loader": "10.2.0", "sinon": "11.1.1", - "spectron": "5.0.0", "style-loader": "1.0.0", "terser-webpack-plugin": "5.1.1", "ts-loader": "4.1.0", @@ -303,7 +305,7 @@ "sharp/color/color-string": "1.5.5" }, "engines": { - "node": "16.5.0" + "node": "16.9.1" }, "build": { "appId": "org.whispersystems.signal-desktop", diff --git a/preload.js b/preload.js index c82c5c919..92c333aa8 100644 --- a/preload.js +++ b/preload.js @@ -121,7 +121,7 @@ try { window.open = () => null; // Playwright uses `eval` for `.evaluate()` API - if (!config.enableCI) { + if (!config.enableCI && config.environment !== 'test') { // eslint-disable-next-line no-eval, no-multi-assign window.eval = global.eval = () => null; } diff --git a/preload_test.js b/preload_test.js index 13cbd00ea..21aa7c22a 100644 --- a/preload_test.js +++ b/preload_test.js @@ -3,31 +3,26 @@ /* global window */ +const { ipcRenderer } = require('electron'); + +window.assert = require('chai').assert; + // This is a hack to let us run TypeScript tests in the renderer process. See the // code in `test/index.html`. -const pendingDescribeCalls = []; -window.describe = (...args) => { - pendingDescribeCalls.push(args); -}; /* eslint-disable global-require, import/no-extraneous-dependencies */ const fastGlob = require('fast-glob'); -fastGlob - .sync('./ts/test-{both,electron}/**/*_test.js', { - absolute: true, - cwd: __dirname, - }) - .forEach(require); - -delete window.describe; - window.test = { - pendingDescribeCalls, - fastGlob, - normalizePath: require('normalize-path'), - fse: require('fs-extra'), - path: require('path'), - basePath: __dirname, - attachmentsPath: window.Signal.Migrations.attachmentsPath, + onComplete(info) { + return ipcRenderer.invoke('ci:test-electron:done', info); + }, + prepareTests() { + fastGlob + .sync('./ts/test-{both,electron}/**/*_test.js', { + absolute: true, + cwd: __dirname, + }) + .forEach(require); + }, }; diff --git a/test/index.html b/test/index.html index d25d53ca7..4b03d434e 100644 --- a/test/index.html +++ b/test/index.html @@ -161,11 +161,6 @@ {{/isError}} - - + + @@ -193,39 +195,13 @@ src="../js/expiring_tap_to_view_messages.js" data-cover > - - - - - - @@ -236,11 +212,33 @@ diff --git a/test/_test.js b/test/test.js similarity index 55% rename from test/_test.js rename to test/test.js index a6096e0b1..bcbe639b6 100644 --- a/test/_test.js +++ b/test/test.js @@ -1,47 +1,7 @@ // Copyright 2014-2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -/* global chai, Whisper, _, Backbone */ - -mocha.setup('bdd'); -window.assert = chai.assert; - -const OriginalReporter = mocha._reporter; - -const SauceReporter = function Constructor(runner) { - const failedTests = []; - - runner.on('end', () => { - window.mochaResults = runner.stats; - window.mochaResults.reports = failedTests; - }); - - runner.on('fail', (test, err) => { - const flattenTitles = item => { - const titles = []; - while (item.parent.title) { - titles.push(item.parent.title); - // eslint-disable-next-line no-param-reassign - item = item.parent; - } - return titles.reverse(); - }; - failedTests.push({ - name: test.title, - result: false, - message: err.message, - stack: err.stack, - titles: flattenTitles(test), - }); - }); - - // eslint-disable-next-line no-new - new OriginalReporter(runner); -}; - -SauceReporter.prototype = OriginalReporter.prototype; - -mocha.reporter(SauceReporter); +/* global Whisper, _, Backbone */ // Override the database id. window.Whisper = window.Whisper || {}; diff --git a/ts/build/test-electron.ts b/ts/build/test-electron.ts new file mode 100644 index 000000000..7ca82fbfe --- /dev/null +++ b/ts/build/test-electron.ts @@ -0,0 +1,54 @@ +// Copyright 2021 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only +/* eslint-disable no-console */ + +import { execFileSync } from 'child_process'; +import { join } from 'path'; + +const ROOT_DIR = join(__dirname, '..', '..'); + +const ELECTRON = join( + ROOT_DIR, + 'node_modules', + '.bin', + process.platform === 'win32' ? 'electron.cmd' : 'electron' +); + +const stdout = execFileSync(ELECTRON, [ROOT_DIR], { + cwd: ROOT_DIR, + env: { + ...process.env, + NODE_ENV: 'test', + }, + encoding: 'utf8', +}); + +const match = stdout.match(/ci:test-electron:done=(.*)?\n/); + +if (!match) { + throw new Error('No test results were found in stdout'); +} + +const { + passed, + failed, +}: { + passed: Array; + failed: Array<{ testName: string; error: string }>; +} = JSON.parse(match[1]); + +const total = passed.length + failed.length; + +for (const { testName, error } of failed) { + console.error(`- ${testName}`); + console.error(error); + console.error(''); +} + +console.log( + `Passed ${passed.length} | Failed ${failed.length} | Total ${total}` +); + +if (failed.length !== 0) { + process.exit(1); +} diff --git a/ts/build/test-release.ts b/ts/build/test-release.ts new file mode 100644 index 000000000..16b8bd91d --- /dev/null +++ b/ts/build/test-release.ts @@ -0,0 +1,80 @@ +// Copyright 2021 Signal Messenger, LLC +// SPDX-License-Identifier: AGPL-3.0-only +/* eslint-disable no-console */ + +import asar from 'asar'; +import assert from 'assert'; +import { join } from 'path'; +import { _electron as electron } from 'playwright'; + +import packageJson from '../../package.json'; + +const ENVIRONMENT = 'production'; +const RELEASE_DIR = join(__dirname, '..', '..', 'release'); + +let archive: string; +let exe: string; +if (process.platform === 'darwin') { + archive = join( + 'mac', + `${packageJson.productName}.app`, + 'Contents', + 'Resources', + 'app.asar' + ); + exe = join( + 'mac', + `${packageJson.productName}.app`, + 'Contents', + 'MacOS', + packageJson.productName + ); +} else if (process.platform === 'win32') { + archive = join('win-unpacked', 'resources', 'app.asar'); + exe = join('win-unpacked', `${packageJson.productName}.exe`); +} else if (process.platform === 'linux') { + archive = join('linux-unpacked', 'resources', 'app.asar'); + exe = join('linux-unpacked', packageJson.name); +} else { + throw new Error(`Unsupported platform: ${process.platform}`); +} + +const files = [ + join('config', 'default.json'), + join('config', `${ENVIRONMENT}.json`), + join('config', `local-${ENVIRONMENT}.json`), +]; + +for (const fileName of files) { + console.log(`Checking that ${fileName} exists in asar ${archive}`); + try { + asar.statFile(join(RELEASE_DIR, archive), fileName); + } catch (e) { + console.log(e); + throw new Error(`Missing file ${fileName}`); + } +} + +// A simple test to verify a visible window is opened with a title +const main = async () => { + const executablePath = join(RELEASE_DIR, exe); + console.log('Starting path', executablePath); + const app = await electron.launch({ + executablePath, + locale: 'en', + }); + + console.log('Waiting for a first window'); + const window = await app.firstWindow(); + await window.waitForLoadState(); + + console.log('Checking window title'); + assert.strictEqual(await window.title(), packageJson.productName); + + await app.close(); +}; + +main().catch(error => { + console.error(error); + process.exit(1); +}); diff --git a/ts/environment.ts b/ts/environment.ts index 8a64af416..64149e550 100644 --- a/ts/environment.ts +++ b/ts/environment.ts @@ -9,7 +9,6 @@ export enum Environment { Production = 'production', Staging = 'staging', Test = 'test', - TestLib = 'test-lib', } let environment: undefined | Environment; @@ -41,4 +40,4 @@ export const parseEnvironment = makeEnumParser( ); export const isTestEnvironment = (env: Environment): boolean => - env === Environment.Test || env === Environment.TestLib; + env === Environment.Test; diff --git a/ts/logging/main_process_logging.ts b/ts/logging/main_process_logging.ts index 95b86b703..084198364 100644 --- a/ts/logging/main_process_logging.ts +++ b/ts/logging/main_process_logging.ts @@ -43,9 +43,7 @@ let globalLogger: undefined | pino.Logger; let shouldRestart = false; const isRunningFromConsole = - Boolean(process.stdout.isTTY) || - getEnvironment() === Environment.Test || - getEnvironment() === Environment.TestLib; + Boolean(process.stdout.isTTY) || getEnvironment() === Environment.Test; export async function initialize( getMainWindow: () => undefined | BrowserWindow diff --git a/ts/services/calling.ts b/ts/services/calling.ts index 6f7ea01c4..b8cbe9f6d 100644 --- a/ts/services/calling.ts +++ b/ts/services/calling.ts @@ -1,7 +1,8 @@ // Copyright 2020-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { desktopCapturer, ipcRenderer } from 'electron'; +import type { DesktopCapturerSource } from 'electron'; +import { ipcRenderer } from 'electron'; import type { AudioDevice, CallId, @@ -1097,11 +1098,8 @@ export class CallingClass { } async getPresentingSources(): Promise> { - const sources = await desktopCapturer.getSources({ - fetchWindowIcons: true, - thumbnailSize: { height: 102, width: 184 }, - types: ['window', 'screen'], - }); + const sources: ReadonlyArray = + await ipcRenderer.invoke('getScreenCaptureSources'); const presentableSources: Array = []; diff --git a/ts/test-both/environment_test.ts b/ts/test-both/environment_test.ts index 5fbebefb2..5a9e5fcbc 100644 --- a/ts/test-both/environment_test.ts +++ b/ts/test-both/environment_test.ts @@ -37,10 +37,6 @@ describe('environment utilities', () => { it('parses "test" as Environment.Test', () => { assert.equal(parseEnvironment('test'), Environment.Test); }); - - it('parses "test-lib" as Environment.TestLib', () => { - assert.equal(parseEnvironment('test-lib'), Environment.TestLib); - }); }); describe('isTestEnvironment', () => { @@ -52,7 +48,6 @@ describe('environment utilities', () => { it('returns true for test environments', () => { assert.isTrue(isTestEnvironment(Environment.Test)); - assert.isTrue(isTestEnvironment(Environment.TestLib)); }); }); }); diff --git a/ts/test-electron/state/ducks/calling_test.ts b/ts/test-electron/state/ducks/calling_test.ts index c896e9c47..23e807baa 100644 --- a/ts/test-electron/state/ducks/calling_test.ts +++ b/ts/test-electron/state/ducks/calling_test.ts @@ -1352,7 +1352,7 @@ describe('calling duck', () => { describe('thunk', () => { function noopTest(connectionState: GroupCallConnectionState) { - return async function test(this: Mocha.ITestCallbackContext) { + return async function test(this: Mocha.Context) { const dispatch = sinon.spy(); await peekNotConnectedGroupCall({ diff --git a/libtextsecure/test/sendmessage_test.js b/ts/test-electron/textsecure/SendMessage_test.ts similarity index 76% rename from libtextsecure/test/sendmessage_test.js rename to ts/test-electron/textsecure/SendMessage_test.ts index e856310c4..13ae847ad 100644 --- a/libtextsecure/test/sendmessage_test.js +++ b/ts/test-electron/textsecure/SendMessage_test.ts @@ -1,8 +1,10 @@ -// Copyright 2019-2020 Signal Messenger, LLC +// Copyright 2019-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -/* global textsecure, WebAPI */ -/* eslint-disable no-console */ +import { assert } from 'chai'; + +import MessageSender from '../../textsecure/SendMessage'; +import type { WebAPIType } from '../../textsecure/WebAPI'; const BUCKET_SIZES = [ 541, 568, 596, 626, 657, 690, 725, 761, 799, 839, 881, 925, 972, 1020, 1071, @@ -34,17 +36,11 @@ const BUCKET_SIZES = [ 80095580, 84100359, 88305377, 92720646, 97356678, 102224512, 107335738, ]; -describe('sendmessage', () => { - let originalWebAPIConnect = null; - let sendmessage = null; - before(() => { - originalWebAPIConnect = WebAPI.connect; - WebAPI.connect = () => null; +describe('SendMessage', () => { + let sendMessage: MessageSender; - sendmessage = new textsecure.MessageSender(); - }); - after(() => { - WebAPI.connect = originalWebAPIConnect; + before(() => { + sendMessage = new MessageSender({} as unknown as WebAPIType); }); describe('#_getAttachmentSizeBucket', () => { @@ -52,7 +48,7 @@ describe('sendmessage', () => { for (let size = 0, max = BUCKET_SIZES[0]; size < max; size += 1) { assert.strictEqual( BUCKET_SIZES[0], - sendmessage._getAttachmentSizeBucket(size) + sendMessage._getAttachmentSizeBucket(size) ); } }); @@ -60,17 +56,18 @@ describe('sendmessage', () => { it('properly calculates entire table', () => { let count = 0; + const failures = new Array(); for (let i = 0, max = BUCKET_SIZES.length - 1; i < max; i += 1) { // Exact if ( BUCKET_SIZES[i] !== - sendmessage._getAttachmentSizeBucket(BUCKET_SIZES[i]) + sendMessage._getAttachmentSizeBucket(BUCKET_SIZES[i]) ) { count += 1; - console.log( + failures.push( `${ BUCKET_SIZES[i] - } does not equal ${sendmessage._getAttachmentSizeBucket( + } does not equal ${sendMessage._getAttachmentSizeBucket( BUCKET_SIZES[i] )}` ); @@ -79,13 +76,13 @@ describe('sendmessage', () => { // Just under if ( BUCKET_SIZES[i] !== - sendmessage._getAttachmentSizeBucket(BUCKET_SIZES[i] - 1) + sendMessage._getAttachmentSizeBucket(BUCKET_SIZES[i] - 1) ) { count += 1; - console.log( + failures.push( `${ BUCKET_SIZES[i] - } does not equal ${sendmessage._getAttachmentSizeBucket( + } does not equal ${sendMessage._getAttachmentSizeBucket( BUCKET_SIZES[i] - 1 )}` ); @@ -94,21 +91,20 @@ describe('sendmessage', () => { // Just over if ( BUCKET_SIZES[i + 1] !== - sendmessage._getAttachmentSizeBucket(BUCKET_SIZES[i] + 1) + sendMessage._getAttachmentSizeBucket(BUCKET_SIZES[i] + 1) ) { count += 1; - console.log( + failures.push( `${ BUCKET_SIZES[i + 1] - } does not equal ${sendmessage._getAttachmentSizeBucket( + } does not equal ${sendMessage._getAttachmentSizeBucket( BUCKET_SIZES[i] + 1 )}` ); } } - console.log(`Failures: ${count}`); - assert.strictEqual(count, 0); + assert.strictEqual(count, 0, failures.join('\n')); }); }); }); diff --git a/ts/util/lint/exceptions.json b/ts/util/lint/exceptions.json index eb7fb3790..d507a0da3 100644 --- a/ts/util/lint/exceptions.json +++ b/ts/util/lint/exceptions.json @@ -827,13 +827,6 @@ "reasonCategory": "falseMatch", "updated": "2018-09-19T18:13:29.628Z" }, - { - "rule": "jQuery-wrap(", - "path": "node_modules/boom/lib/index.js", - "line": " error = exports.wrap(data, statusCode, message);", - "reasonCategory": "falseMatch", - "updated": "2018-09-19T18:13:29.628Z" - }, { "rule": "jQuery-wrap(", "path": "node_modules/cacheable-lookup/source/index.js", @@ -862,13 +855,6 @@ "reasonCategory": "falseMatch", "updated": "2018-09-15T00:38:04.183Z" }, - { - "rule": "jQuery-load(", - "path": "node_modules/configstore/node_modules/signal-exit/index.js", - "line": " load()", - "reasonCategory": "falseMatch", - "updated": "2021-11-13T01:24:25.496Z" - }, { "rule": "jQuery-append(", "path": "node_modules/copy-text-to-clipboard/index.js", @@ -1102,13 +1088,6 @@ "reasonCategory": "usageTrusted", "updated": "2021-04-05T20:48:36.065Z" }, - { - "rule": "jQuery-prepend(", - "path": "node_modules/css/node_modules/source-map/lib/source-map/source-node.js", - "line": " this.prepend(aChunk[i]);", - "reasonCategory": "falseMatch", - "updated": "2018-09-19T18:13:29.628Z" - }, { "rule": "jQuery-load(", "path": "node_modules/debug/dist/debug.js", @@ -1208,34 +1187,6 @@ "reasonCategory": "falseMatch", "updated": "2018-09-19T18:13:29.628Z" }, - { - "rule": "jQuery-load(", - "path": "node_modules/electron-download/node_modules/debug/src/browser.js", - "line": "function load() {", - "reasonCategory": "falseMatch", - "updated": "2019-12-11T01:10:06.091Z" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/electron-download/node_modules/debug/src/browser.js", - "line": "exports.enable(load());", - "reasonCategory": "falseMatch", - "updated": "2019-12-11T01:10:06.091Z" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/electron-download/node_modules/debug/src/node.js", - "line": "function load() {", - "reasonCategory": "falseMatch", - "updated": "2019-12-11T01:10:06.091Z" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/electron-download/node_modules/debug/src/node.js", - "line": "exports.enable(load());", - "reasonCategory": "falseMatch", - "updated": "2019-12-11T01:10:06.091Z" - }, { "rule": "jQuery-append(", "path": "node_modules/enquirer/lib/prompts/autocomplete.js", @@ -1400,6 +1351,13 @@ "updated": "2020-08-26T00:10:28.628Z", "reasonDetail": "isn't react" }, + { + "rule": "jQuery-load(", + "path": "node_modules/execa/node_modules/signal-exit/index.js", + "line": " load()", + "reasonCategory": "falseMatch", + "updated": "2021-12-07T23:11:11.870Z" + }, { "rule": "jQuery-wrap(", "path": "node_modules/expand-range/node_modules/fill-range/index.js", @@ -1504,6 +1462,13 @@ "reasonCategory": "exampleCode", "updated": "2021-10-01T23:53:26.107Z" }, + { + "rule": "jQuery-load(", + "path": "node_modules/foreground-child/node_modules/signal-exit/index.js", + "line": " load()", + "reasonCategory": "falseMatch", + "updated": "2021-12-07T23:11:11.870Z" + }, { "rule": "jQuery-append(", "path": "node_modules/form-data/lib/form_data.js", @@ -4338,11 +4303,11 @@ "updated": "2021-07-16T22:15:43.772Z" }, { - "rule": "thenify-multiArgs", - "path": "node_modules/load-json-file/node_modules/pify/index.js", - "line": "\t\t\t\t} else if (opts.multiArgs) {", + "rule": "jQuery-append(", + "path": "node_modules/load-json-file/node_modules/parse-json/index.js", + "line": "\tfileName: errorEx.append('in %s')", "reasonCategory": "falseMatch", - "updated": "2018-09-19T18:06:35.446Z" + "updated": "2021-12-07T23:11:11.870Z" }, { "rule": "eval", @@ -4393,13 +4358,6 @@ "updated": "2021-05-24T17:14:21.037Z", "reasonDetail": "This is inside of a regular expression and is not jQuery." }, - { - "rule": "jQuery-load(", - "path": "node_modules/mac-screen-capture-permissions/node_modules/signal-exit/index.js", - "line": " load()", - "reasonCategory": "falseMatch", - "updated": "2021-11-13T01:24:25.496Z" - }, { "rule": "jQuery-after(", "path": "node_modules/mime/src/test.js", @@ -4573,177 +4531,12 @@ "reasonCategory": "falseMatch", "updated": "2020-09-14T16:19:54.461Z" }, - { - "rule": "jQuery-$(", - "path": "node_modules/nugget/node_modules/ajv/dist/ajv.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/nugget/node_modules/ajv/dist/ajv.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "React-ref", - "path": "node_modules/nugget/node_modules/ajv/dist/nodent.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/nugget/node_modules/ajv/dist/nodent.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/nugget/node_modules/ajv/dist/nodent.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/nugget/node_modules/ajv/dist/nodent.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-prepend(", - "path": "node_modules/nugget/node_modules/ajv/dist/nodent.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/nugget/node_modules/ajv/dist/regenerator.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/nugget/node_modules/ajv/dist/regenerator.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/nugget/node_modules/ajv/dist/regenerator.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-insertAfter(", - "path": "node_modules/nugget/node_modules/ajv/dist/regenerator.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-insertAfter(", - "path": "node_modules/nugget/node_modules/ajv/dist/regenerator.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-insertAfter(", - "path": "node_modules/nugget/node_modules/ajv/dist/regenerator.min.js", - "reasonCategory": "falseMatch", - "updated": "2020-09-11T17:24:56.124Z" - }, - { - "rule": "jQuery-insertBefore(", - "path": "node_modules/nugget/node_modules/ajv/dist/regenerator.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-insertBefore(", - "path": "node_modules/nugget/node_modules/ajv/dist/regenerator.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-prepend(", - "path": "node_modules/nugget/node_modules/ajv/dist/regenerator.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-wrap(", - "path": "node_modules/nugget/node_modules/ajv/dist/regenerator.min.js", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, { "rule": "jQuery-load(", - "path": "node_modules/nugget/node_modules/debug/src/browser.js", - "line": "function load() {", + "path": "node_modules/os-locale/node_modules/signal-exit/index.js", + "line": " load()", "reasonCategory": "falseMatch", - "updated": "2019-12-11T01:10:06.091Z" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/nugget/node_modules/debug/src/browser.js", - "line": "exports.enable(load());", - "reasonCategory": "falseMatch", - "updated": "2019-12-11T01:10:06.091Z" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/nugget/node_modules/debug/src/node.js", - "line": "exports.enable(load());", - "reasonCategory": "falseMatch", - "updated": "2019-12-11T01:10:06.091Z" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/nugget/node_modules/debug/src/node.js", - "line": "function load() {", - "reasonCategory": "falsematch", - "updated": "2020-02-18T23:18:32.165Z" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/nugget/node_modules/form-data/lib/form_data.js", - "line": " append(header);", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/nugget/node_modules/form-data/lib/form_data.js", - "line": " append(footer);", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/nugget/node_modules/form-data/lib/form_data.js", - "line": " append(value);", - "reasonCategory": "falseMatch", - "updated": "2020-09-11T17:24:56.124Z" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/nugget/node_modules/request/lib/multipart.js", - "line": " return chunked ? body.append(part) : body.push(Buffer.from(part))", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/nugget/node_modules/request/request.js", - "line": " requestForm.append(key, value.value, value.options)", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/nugget/node_modules/request/request.js", - "line": " requestForm.append(key, value)", - "reasonCategory": "falseMatch", - "updated": "2019-07-19T17:16:02.404Z" + "updated": "2021-12-07T23:11:11.870Z" }, { "rule": "DOM-innerHTML", @@ -5144,1252 +4937,6 @@ "reasonCategory": "falseMatch", "updated": "2021-03-09T20:56:35.403Z" }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/client/elementHandle.js", - "line": " async innerHTML() {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/client/elementHandle.js", - "line": " return this._wrapApiCall('elementHandle.innerHTML', async (channel) => {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/client/elementHandle.js", - "line": " return (await channel.innerHTML()).value;", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "eval", - "path": "node_modules/playwright/lib/client/elementHandle.js", - "line": " async $eval(selector, pageFunction, arg) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "eval", - "path": "node_modules/playwright/lib/client/elementHandle.js", - "line": " async $$eval(selector, pageFunction, arg) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/client/elementHandle.js", - "line": " async $(selector) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/client/elementHandle.js", - "line": " async $$(selector) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/client/frame.js", - "line": " async innerHTML(selector, options = {}) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/client/frame.js", - "line": " return this._wrapApiCall(this._apiName('innerHTML'), async (channel) => {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/client/frame.js", - "line": " return (await channel.innerHTML({ selector, ...options })).value;", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "eval", - "path": "node_modules/playwright/lib/client/frame.js", - "line": " async $eval(selector, pageFunction, arg) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "eval", - "path": "node_modules/playwright/lib/client/frame.js", - "line": " async $$eval(selector, pageFunction, arg) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/client/frame.js", - "line": " async $(selector) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/client/frame.js", - "line": " async $$(selector) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/client/page.js", - "line": " async innerHTML(selector, options) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/client/page.js", - "line": " return this._attributeToPage(() => this._mainFrame.innerHTML(selector, options));", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "eval", - "path": "node_modules/playwright/lib/client/page.js", - "line": " async $eval(selector, pageFunction, arg) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "eval", - "path": "node_modules/playwright/lib/client/page.js", - "line": " return this._attributeToPage(() => this._mainFrame.$eval(selector, pageFunction, arg));", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "eval", - "path": "node_modules/playwright/lib/client/page.js", - "line": " async $$eval(selector, pageFunction, arg) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "eval", - "path": "node_modules/playwright/lib/client/page.js", - "line": " return this._attributeToPage(() => this._mainFrame.$$eval(selector, pageFunction, arg));", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/client/page.js", - "line": " async $(selector) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/client/page.js", - "line": " return this._attributeToPage(() => this._mainFrame.$(selector));", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/client/page.js", - "line": " async $$(selector) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/client/page.js", - "line": " return this._attributeToPage(() => this._mainFrame.$$(selector));", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/dispatchers/elementHandlerDispatcher.js", - "line": " async innerHTML(params, metadata) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/dispatchers/elementHandlerDispatcher.js", - "line": " return { value: await this._elementHandle.innerHTML() };", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/dispatchers/elementHandlerDispatcher.js", - "line": " const handle = await this._elementHandle.$(params.selector);", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/dispatchers/elementHandlerDispatcher.js", - "line": " const elements = await this._elementHandle.$$(params.selector);", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/dispatchers/frameDispatcher.js", - "line": " async innerHTML(params, metadata) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/dispatchers/frameDispatcher.js", - "line": " return { value: await this._frame.innerHTML(metadata, params.selector, params) };", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/dispatchers/frameDispatcher.js", - "line": " return { element: elementHandlerDispatcher_1.ElementHandleDispatcher.createNullable(this._scope, await this._frame.$(params.selector)) };", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/dispatchers/frameDispatcher.js", - "line": " const elements = await this._frame.$$(params.selector);", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/generated/consoleApiSource.js", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/playwright/lib/generated/consoleApiSource.js", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "eval", - "path": "node_modules/playwright/lib/generated/injectedScriptSource.js", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/playwright/lib/generated/injectedScriptSource.js", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/playwright/lib/generated/recorderSource.js", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "eval", - "path": "node_modules/playwright/lib/generated/utilityScriptSource.js", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/playwright/lib/server/common/selectorParser.js", - "line": " append();", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/playwright/lib/server/common/selectorParser.js", - "line": " append();", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-append(", - "path": "node_modules/playwright/lib/server/common/selectorParser.js", - "line": " append();", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/server/dom.js", - "line": " async innerHTML() {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/server/dom.js", - "line": " return { value: element.innerHTML };", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/server/dom.js", - "line": " return element.innerHTML;", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/server/dom.js", - "line": " async $(selector) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/server/dom.js", - "line": " async $$(selector) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-document.write(", - "path": "node_modules/playwright/lib/server/frames.js", - "line": " document.write(html);", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/server/frames.js", - "line": " async innerHTML(metadata, selector, options = {}) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/server/frames.js", - "line": " progress.log(` retrieving innerHTML from \"${selector}\"`);", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-outerHTML", - "path": "node_modules/playwright/lib/server/frames.js", - "line": " retVal += document.documentElement.outerHTML;", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "eval", - "path": "node_modules/playwright/lib/server/frames.js", - "line": " let result = self.eval(expression);", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/server/frames.js", - "line": " async $(selector) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/server/frames.js", - "line": " const handle = await this.$(selector);", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/server/frames.js", - "line": " async $$(selector) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/server/frames.js", - "line": " const element = await this.$(selector);", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/playwright/lib/server/snapshot/snapshotStorage.js", - "line": " async load(tracePrefix, resourcesDir) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-prepend(", - "path": "node_modules/playwright/lib/server/supplements/recorder/csharp.js", - "line": " prepend(text) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-prepend(", - "path": "node_modules/playwright/lib/server/supplements/recorder/javascript.js", - "line": " prepend(text) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-prepend(", - "path": "node_modules/playwright/lib/server/supplements/recorder/python.js", - "line": " prepend(text) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "jQuery-load(", - "path": "node_modules/playwright/lib/server/trace/viewer/traceViewer.js", - "line": " await snapshotStorage.load(tracePrefix, resourcesDir);", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/third_party/highlightjs/highlightjs/core.js", - "line": " resultNode.innerHTML = result.value;", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/third_party/highlightjs/highlightjs/core.js", - "line": " block.innerHTML = block.innerHTML.replace(/\\n/g, '').replace(//g, '\\n');", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/third_party/highlightjs/highlightjs/core.js", - "line": " element.innerHTML = result.value;", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/third_party/highlightjs/highlightjs/core.js", - "line": " domProps: { innerHTML: this.highlighted }", - "reasonCategory": "usageTrusted", - "updated": "2021-12-01T01:31:12.757Z" - }, - { - "rule": "jQuery-$(", - "path": "node_modules/playwright/lib/third_party/highlightjs/highlightjs/languages/javascript.js", - "line": " begin: /\\$[(.]/ // relevance booster for a pattern common to JS libs: `$(something)` and `$.something`", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/web/recorder/app.bundle.js", - "line": "'defaultValue', 'defaultChecked', 'innerHTML', 'suppressContentEditableWarning', 'suppressHydrationWarning', 'style'];", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/web/recorder/app.bundle.js", - "line": " * Set the innerHTML property of a node", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/web/recorder/app.bundle.js", - "line": " if (!('innerHTML' in node)) {", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/web/recorder/app.bundle.js", - "line": " // IE does not have innerHTML for SVG nodes, so instead we inject the", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/web/recorder/app.bundle.js", - "line": " reusableSVGContainer.innerHTML = '' + html.valueOf().toString() + '';", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/web/recorder/app.bundle.js", - "line": " node.innerHTML = html;", - "reasonCategory": "falseMatch", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/web/recorder/app.bundle.js", - "line": " innerhtml: 'innerHTML',", - "reasonCategory": "usageTrusted", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/web/recorder/app.bundle.js", - "line": " error('Directly setting property `innerHTML` is not permitted. ' + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.');", - "reasonCategory": "usageTrusted", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/web/recorder/app.bundle.js", - "line": " testElement.innerHTML = html;", - "reasonCategory": "usageTrusted", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/web/recorder/app.bundle.js", - "line": " return testElement.innerHTML;", - "reasonCategory": "usageTrusted", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/web/recorder/app.bundle.js", - "line": " // Create the script via .innerHTML so its \"parser-inserted\" flag is", - "reasonCategory": "usageTrusted", - "updated": "2021-04-06T04:01:59.934Z" - }, - { - "rule": "DOM-innerHTML", - "path": "node_modules/playwright/lib/web/recorder/app.bundle.js", - "line": " div.innerHTML = '