From 995a914f63224fb38b280b61fbf9ee2c4ffabae4 Mon Sep 17 00:00:00 2001 From: Thomas Watson Date: Wed, 4 Dec 2019 18:18:38 +0100 Subject: [PATCH] Clean up uses of deprecated API's in node core (#51431) (#52192) Ensure no deprecated Node.js core API's are used in Kibana. This is achieved by throwing an error in either development mode or in CI if one of the deprecated API's is called, and as such, new PR's should no longer be able to be merged if they use deprecated API's. Some of these API's (like the `Buffer` constructor`) is a security risk. --- package.json | 5 +- .../kbn-babel-code-parser/src/strategies.js | 17 +- .../tasks/build/rewrite_package_json.js | 12 +- .../http/integration_tests/router.test.ts | 2 +- src/dev/ci_setup/setup_env.sh | 2 + .../__tests__/proxy_config_collection.js | 2 +- .../__jest__/step_time_field.test.js | 1 + .../usage/telemetry_usage_collector.test.ts | 2 +- .../series_functions/__tests__/yaxis.js | 8 +- src/legacy/server/sass/build.js | 38 +- .../ui/public/chrome/__mocks__/index.js | 50 +++ .../utils/deep_clone_with_buffers.test.ts | 4 +- src/legacy/utils/deep_clone_with_buffers.ts | 2 +- .../dynamic_dll_plugin/dll_compiler.js | 11 +- .../actions/replace_panel_action.test.tsx | 23 +- .../embeddable/grid/dashboard_grid.test.tsx | 21 +- .../viewport/dashboard_viewport.test.tsx | 8 +- .../query_string_input.test.tsx.snap | 408 ++++++++++++++++++ .../query_bar_top_row.test.tsx | 4 +- .../query_string_input.test.tsx | 2 + .../saved_object_finder.test.tsx | 2 + utilities/visual_regression.js | 34 +- .../__test__/createErrorGroupWatch.test.ts | 2 +- .../index_management/__mocks__/ui/notify.js | 2 + .../public/components/report_info_button.tsx | 1 - .../server/lib/esqueue/__tests__/worker.js | 24 +- .../index_privileges.test.tsx.snap | 2 +- .../privileges/es/index_privileges.test.tsx | 14 +- .../privileges/es/index_privileges.tsx | 4 +- .../__tests__/get_xpack.js | 14 +- x-pack/package.json | 2 +- .../authentication/authenticator.test.ts | 32 +- yarn.lock | 90 +--- 33 files changed, 638 insertions(+), 207 deletions(-) diff --git a/package.json b/package.json index 868735bf123e..ece9257c6556 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "typespec": "typings-tester --config x-pack/legacy/plugins/canvas/public/lib/aeroelastic/tsconfig.json x-pack/legacy/plugins/canvas/public/lib/aeroelastic/__fixtures__/typescript/typespec_tests.ts", "checkLicenses": "node scripts/check_licenses --dev", "build": "node scripts/build --all-platforms", - "start": "node --trace-warnings --trace-deprecation scripts/kibana --dev ", + "start": "node --trace-warnings --throw-deprecation scripts/kibana --dev", "debug": "node --nolazy --inspect scripts/kibana --dev", "debug-break": "node --nolazy --inspect-brk scripts/kibana --dev", "karma": "karma start", @@ -401,7 +401,6 @@ "gulp-sourcemaps": "2.6.5", "has-ansi": "^3.0.0", "iedriver": "^3.14.1", - "image-diff": "1.6.3", "intl-messageformat-parser": "^1.4.0", "is-path-inside": "^2.1.0", "istanbul-instrumenter-loader": "3.0.1", @@ -429,7 +428,7 @@ "node-sass": "^4.9.4", "normalize-path": "^3.0.0", "nyc": "^14.1.1", - "pixelmatch": "4.0.2", + "pixelmatch": "^5.1.0", "pkg-up": "^2.0.0", "pngjs": "^3.4.0", "postcss": "^7.0.5", diff --git a/packages/kbn-babel-code-parser/src/strategies.js b/packages/kbn-babel-code-parser/src/strategies.js index 89621bc53bd5..f116abde9e0e 100644 --- a/packages/kbn-babel-code-parser/src/strategies.js +++ b/packages/kbn-babel-code-parser/src/strategies.js @@ -20,6 +20,7 @@ import { canRequire } from './can_require'; import { dependenciesVisitorsGenerator } from './visitors'; import { dirname, isAbsolute, resolve } from 'path'; +import { builtinModules } from 'module'; export function _calculateTopLevelDependency(inputDep, outputDep = '') { // The path separator will be always the forward slash @@ -48,14 +49,18 @@ export function _calculateTopLevelDependency(inputDep, outputDep = '') { return _calculateTopLevelDependency(depSplitPaths.join(pathSeparator), outputDep); } -export async function dependenciesParseStrategy(cwd, parseSingleFile, mainEntry, wasParsed, results) { - // Retrieve native nodeJS modules - const natives = process.binding('natives'); - +export async function dependenciesParseStrategy( + cwd, + parseSingleFile, + mainEntry, + wasParsed, + results +) { // Get dependencies from a single file and filter // out node native modules from the result - const dependencies = (await parseSingleFile(mainEntry, dependenciesVisitorsGenerator)) - .filter(dep => !natives[dep]); + const dependencies = (await parseSingleFile(mainEntry, dependenciesVisitorsGenerator)).filter( + dep => !builtinModules.includes(dep) + ); // Return the list of all the new entries found into // the current mainEntry that we could use to look for diff --git a/packages/kbn-plugin-helpers/tasks/build/rewrite_package_json.js b/packages/kbn-plugin-helpers/tasks/build/rewrite_package_json.js index db33b209951e..64656baee6fd 100644 --- a/packages/kbn-plugin-helpers/tasks/build/rewrite_package_json.js +++ b/packages/kbn-plugin-helpers/tasks/build/rewrite_package_json.js @@ -41,19 +41,9 @@ module.exports = function rewritePackage(buildSource, buildVersion, kibanaVersio delete pkg.scripts; delete pkg.devDependencies; - file.contents = toBuffer(JSON.stringify(pkg, null, 2)); + file.contents = Buffer.from(JSON.stringify(pkg, null, 2)); } return file; }); }; - -function toBuffer(string) { - if (typeof Buffer.from === 'function') { - return Buffer.from(string, 'utf8'); - } else { - // this was deprecated in node v5 in favor - // of Buffer.from(string, encoding) - return new Buffer(string, 'utf8'); - } -} diff --git a/src/core/server/http/integration_tests/router.test.ts b/src/core/server/http/integration_tests/router.test.ts index 7d95110b98a1..6117190c57ba 100644 --- a/src/core/server/http/integration_tests/router.test.ts +++ b/src/core/server/http/integration_tests/router.test.ts @@ -329,7 +329,7 @@ describe('Response factory', () => { const router = createRouter('/'); router.get({ path: '/', validate: false }, (context, req, res) => { - const buffer = new Buffer('abc'); + const buffer = Buffer.from('abc'); return res.ok({ body: buffer, diff --git a/src/dev/ci_setup/setup_env.sh b/src/dev/ci_setup/setup_env.sh index 6cfcaca5843b..e5edf5bd9c26 100644 --- a/src/dev/ci_setup/setup_env.sh +++ b/src/dev/ci_setup/setup_env.sh @@ -14,6 +14,8 @@ cacheDir="$HOME/.kibana" RED='\033[0;31m' C_RESET='\033[0m' # Reset color +export NODE_OPTIONS="$NODE_OPTIONS --throw-deprecation" + ### ### Since the Jenkins logging output collector doesn't look like a TTY ### Node/Chalk and other color libs disable their color output. But Jenkins diff --git a/src/legacy/core_plugins/console/server/__tests__/proxy_config_collection.js b/src/legacy/core_plugins/console/server/__tests__/proxy_config_collection.js index 91797f897d8b..e575b0f707aa 100644 --- a/src/legacy/core_plugins/console/server/__tests__/proxy_config_collection.js +++ b/src/legacy/core_plugins/console/server/__tests__/proxy_config_collection.js @@ -28,7 +28,7 @@ import { ProxyConfigCollection } from '../proxy_config_collection'; describe('ProxyConfigCollection', function () { beforeEach(function () { - sinon.stub(fs, 'readFileSync').callsFake(() => new Buffer(0)); + sinon.stub(fs, 'readFileSync').callsFake(() => Buffer.alloc(0)); }); afterEach(function () { diff --git a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/__jest__/step_time_field.test.js b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/__jest__/step_time_field.test.js index 5677d2293a72..1f9d80440f6c 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/__jest__/step_time_field.test.js +++ b/src/legacy/core_plugins/kibana/public/management/sections/index_patterns/create_index_pattern_wizard/components/step_time_field/__jest__/step_time_field.test.js @@ -43,6 +43,7 @@ const indexPatternsService = { make: async () => ({ fieldsFetcher: { fetch: noop, + fetchForWildcard: noop, }, }), }; diff --git a/src/legacy/core_plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts b/src/legacy/core_plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts index 2b2e946198e0..cf6059faf0c0 100644 --- a/src/legacy/core_plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts +++ b/src/legacy/core_plugins/telemetry/server/collectors/usage/telemetry_usage_collector.test.ts @@ -75,7 +75,7 @@ describe('telemetry_usage_collector', () => { // empty writeFileSync(tempFiles.empty, ''); // 1 byte too big - writeFileSync(tempFiles.too_big, new Buffer(MAX_FILE_SIZE + 1)); + writeFileSync(tempFiles.too_big, Buffer.alloc(MAX_FILE_SIZE + 1)); // write-only file writeFileSync(tempFiles.unreadable, 'valid: true', { mode: 0o222 }); // valid diff --git a/src/legacy/core_plugins/timelion/server/series_functions/__tests__/yaxis.js b/src/legacy/core_plugins/timelion/server/series_functions/__tests__/yaxis.js index ebc187100c7e..2aa4b9a471c4 100644 --- a/src/legacy/core_plugins/timelion/server/series_functions/__tests__/yaxis.js +++ b/src/legacy/core_plugins/timelion/server/series_functions/__tests__/yaxis.js @@ -95,16 +95,16 @@ describe('yaxis.js', () => { it('throws an error if currency is not three letter code', () => { invoke(fn, [seriesList, 1, null, null, null, null, null, 'currency:abcde']).catch(e => { - expect(e).to.be.an(Error); + expect(e).to.be.an.instanceof(Error); }); invoke(fn, [seriesList, 1, null, null, null, null, null, 'currency:12']).catch(e => { - expect(e).to.be.an(Error); + expect(e).to.be.an.instanceof(Error); }); invoke(fn, [seriesList, 1, null, null, null, null, null, 'currency:$#']).catch(e => { - expect(e).to.be.an(Error); + expect(e).to.be.an.instanceof(Error); }); invoke(fn, [seriesList, 1, null, null, null, null, null, 'currency:ab']).catch(e => { - expect(e).to.be.an(Error); + expect(e).to.be.an.instanceof(Error); }); }); diff --git a/src/legacy/server/sass/build.js b/src/legacy/server/sass/build.js index db1b26e10283..2872ef5daa20 100644 --- a/src/legacy/server/sass/build.js +++ b/src/legacy/server/sass/build.js @@ -30,7 +30,7 @@ import { PUBLIC_PATH_PLACEHOLDER } from '../../../optimize/public_path_placehold const renderSass = promisify(sass.render); const writeFile = promisify(fs.writeFile); -const exists = promisify(fs.exists); +const access = promisify(fs.access); const copyFile = promisify(fs.copyFile); const mkdirAsync = promisify(fs.mkdir); @@ -145,23 +145,27 @@ export class Build { ]; // verify that asset sources exist and import is valid before writing anything - await Promise.all(urlAssets.map(async (asset) => { - if (!await exists(asset.path)) { - throw this._makeError( - 'Invalid url() in css output', - `url("${asset.requestUrl}") resolves to "${asset.path}", which does not exist.\n` + - ` Make sure that the request is relative to "${asset.root}"` - ); - } + await Promise.all( + urlAssets.map(async asset => { + try { + await access(asset.path); + } catch (e) { + throw this._makeError( + 'Invalid url() in css output', + `url("${asset.requestUrl}") resolves to "${asset.path}", which does not exist.\n` + + ` Make sure that the request is relative to "${asset.root}"` + ); + } - if (!isPathInside(asset.path, asset.boundry)) { - throw this._makeError( - 'Invalid url() in css output', - `url("${asset.requestUrl}") resolves to "${asset.path}"\n` + - ` which is outside of "${asset.boundry}"` - ); - } - })); + if (!isPathInside(asset.path, asset.boundry)) { + throw this._makeError( + 'Invalid url() in css output', + `url("${asset.requestUrl}") resolves to "${asset.path}"\n` + + ` which is outside of "${asset.boundry}"` + ); + } + }) + ); // write css await mkdirAsync(this.targetDir, { recursive: true }); diff --git a/src/legacy/ui/public/chrome/__mocks__/index.js b/src/legacy/ui/public/chrome/__mocks__/index.js index e8149970002a..0d3e580d4b4f 100644 --- a/src/legacy/ui/public/chrome/__mocks__/index.js +++ b/src/legacy/ui/public/chrome/__mocks__/index.js @@ -40,3 +40,53 @@ const chrome = { // eslint-disable-next-line import/no-default-export export default chrome; + +// Copied from `src/legacy/ui/public/chrome/chrome.js` +import _ from 'lodash'; +import angular from 'angular'; +import { metadata } from '../../metadata'; + +const internals = _.defaults( + _.cloneDeep(metadata), + { + basePath: '', + rootController: null, + rootTemplate: null, + showAppsLink: null, + xsrfToken: null, + devMode: true, + brand: null, + nav: [], + applicationClasses: [] + } +); + +const waitForBootstrap = new Promise(resolve => { + chrome.bootstrap = function (targetDomElement) { + // import chrome nav controls and hacks now so that they are executed after + // everything else, can safely import the chrome, and interact with services + // and such setup by all other modules + require('uiExports/chromeNavControls'); + require('uiExports/hacks'); + + // sets attribute on body for stylesheet sandboxing + document.body.setAttribute('id', `${internals.app.id}-app`); + + chrome.setupAngular(); + targetDomElement.setAttribute('kbn-chrome', 'true'); + targetDomElement.setAttribute('ng-class', '{ \'hidden-chrome\': !chrome.getVisible() }'); + targetDomElement.className = 'app-wrapper'; + angular.bootstrap(targetDomElement, ['kibana']); + resolve(targetDomElement); + }; +}); + +chrome.dangerouslyGetActiveInjector = () => { + return waitForBootstrap.then((targetDomElement) => { + const $injector = angular.element(targetDomElement).injector(); + if (!$injector) { + return Promise.reject('targetDomElement had no angular context after bootstrapping'); + } + return $injector; + }); +}; diff --git a/src/legacy/utils/deep_clone_with_buffers.test.ts b/src/legacy/utils/deep_clone_with_buffers.test.ts index 8fdf1ae7bfd9..7a0906a715c2 100644 --- a/src/legacy/utils/deep_clone_with_buffers.test.ts +++ b/src/legacy/utils/deep_clone_with_buffers.test.ts @@ -52,7 +52,7 @@ describe('deepCloneWithBuffers()', () => { }); it('copies buffers but keeps them buffers', () => { - const input = new Buffer('i am a teapot', 'utf8'); + const input = Buffer.from('i am a teapot', 'utf8'); const output = deepCloneWithBuffers(input); expect(Buffer.isBuffer(input)).toBe(true); @@ -65,7 +65,7 @@ describe('deepCloneWithBuffers()', () => { const input = { a: { b: { - c: new Buffer('i am a teapot', 'utf8'), + c: Buffer.from('i am a teapot', 'utf8'), }, }, }; diff --git a/src/legacy/utils/deep_clone_with_buffers.ts b/src/legacy/utils/deep_clone_with_buffers.ts index 6938b9371435..2e9120eb32b7 100644 --- a/src/legacy/utils/deep_clone_with_buffers.ts +++ b/src/legacy/utils/deep_clone_with_buffers.ts @@ -24,7 +24,7 @@ import { cloneDeep } from 'lodash'; // type of the customizer function doesn't expect that. function cloneBuffersCustomizer(val: unknown): any { if (Buffer.isBuffer(val)) { - return new Buffer(val); + return Buffer.from(val); } } diff --git a/src/optimize/dynamic_dll_plugin/dll_compiler.js b/src/optimize/dynamic_dll_plugin/dll_compiler.js index 3f3bb3e4e196..425436551511 100644 --- a/src/optimize/dynamic_dll_plugin/dll_compiler.js +++ b/src/optimize/dynamic_dll_plugin/dll_compiler.js @@ -29,7 +29,7 @@ import del from 'del'; const readFileAsync = promisify(fs.readFile); const mkdirAsync = promisify(fs.mkdir); -const existsAsync = promisify(fs.exists); +const accessAsync = promisify(fs.access); const writeFileAsync = promisify(fs.writeFile); export class DllCompiler { @@ -127,13 +127,14 @@ export class DllCompiler { } async ensurePathExists(filePath) { - const exists = await existsAsync(filePath); - - if (!exists) { + try { + await accessAsync(filePath); + } catch (e) { await mkdirAsync(path.dirname(filePath), { recursive: true }); + return false; } - return exists; + return true; } async ensureOutputPathExists() { diff --git a/src/plugins/dashboard_embeddable_container/public/actions/replace_panel_action.test.tsx b/src/plugins/dashboard_embeddable_container/public/actions/replace_panel_action.test.tsx index de29e1dec85a..4438a6c99712 100644 --- a/src/plugins/dashboard_embeddable_container/public/actions/replace_panel_action.test.tsx +++ b/src/plugins/dashboard_embeddable_container/public/actions/replace_panel_action.test.tsx @@ -16,7 +16,6 @@ * specific language governing permissions and limitations * under the License. */ - import { isErrorEmbeddable, EmbeddableFactory } from '../embeddable_plugin'; import { ReplacePanelAction } from './replace_panel_action'; import { DashboardContainer } from '../embeddable'; @@ -29,6 +28,8 @@ import { ContactCardEmbeddableOutput, } from '../embeddable_plugin_test_samples'; import { DashboardOptions } from '../embeddable/dashboard_container_factory'; +import { coreMock } from '../../../../core/public/mocks'; +import { CoreStart } from 'kibana/public'; const embeddableFactories = new Map(); embeddableFactories.set( @@ -39,8 +40,9 @@ const getEmbeddableFactories = () => embeddableFactories.values(); let container: DashboardContainer; let embeddable: ContactCardEmbeddable; - +let coreStart: CoreStart; beforeEach(async () => { + coreStart = coreMock.createStart(); const options: DashboardOptions = { ExitFullScreenButton: () => null, SavedObjectFinder: () => null, @@ -50,7 +52,7 @@ beforeEach(async () => { } as any, inspector: {} as any, notifications: {} as any, - overlays: {} as any, + overlays: coreStart.overlays, savedObjectMetaData: {} as any, uiActions: {} as any, }; @@ -80,11 +82,10 @@ beforeEach(async () => { }); test('Executes the replace panel action', async () => { - let core: any; let SavedObjectFinder: any; let notifications: any; const action = new ReplacePanelAction( - core, + coreStart, SavedObjectFinder, notifications, getEmbeddableFactories @@ -93,11 +94,10 @@ test('Executes the replace panel action', async () => { }); test('Is not compatible when embeddable is not in a dashboard container', async () => { - let core: any; let SavedObjectFinder: any; let notifications: any; const action = new ReplacePanelAction( - core, + coreStart, SavedObjectFinder, notifications, getEmbeddableFactories @@ -113,11 +113,10 @@ test('Is not compatible when embeddable is not in a dashboard container', async }); test('Execute throws an error when called with an embeddable not in a parent', async () => { - let core: any; let SavedObjectFinder: any; let notifications: any; const action = new ReplacePanelAction( - core, + coreStart, SavedObjectFinder, notifications, getEmbeddableFactories @@ -129,11 +128,10 @@ test('Execute throws an error when called with an embeddable not in a parent', a }); test('Returns title', async () => { - let core: any; let SavedObjectFinder: any; let notifications: any; const action = new ReplacePanelAction( - core, + coreStart, SavedObjectFinder, notifications, getEmbeddableFactories @@ -142,11 +140,10 @@ test('Returns title', async () => { }); test('Returns an icon', async () => { - let core: any; let SavedObjectFinder: any; let notifications: any; const action = new ReplacePanelAction( - core, + coreStart, SavedObjectFinder, notifications, getEmbeddableFactories diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/grid/dashboard_grid.test.tsx b/src/plugins/dashboard_embeddable_container/public/embeddable/grid/dashboard_grid.test.tsx index e4338dc89153..c1a3d88979f4 100644 --- a/src/plugins/dashboard_embeddable_container/public/embeddable/grid/dashboard_grid.test.tsx +++ b/src/plugins/dashboard_embeddable_container/public/embeddable/grid/dashboard_grid.test.tsx @@ -21,7 +21,7 @@ import sizeMe from 'react-sizeme'; import React from 'react'; -import { nextTick, mountWithIntl } from 'test_utils/enzyme_helpers'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { skip } from 'rxjs/operators'; import { EmbeddableFactory, GetEmbeddableFactory } from '../../embeddable_plugin'; import { DashboardGrid, DashboardGridProps } from './dashboard_grid'; @@ -65,10 +65,14 @@ function prepare(props?: Partial) { } as any, notifications: {} as any, overlays: {} as any, - inspector: {} as any, + inspector: { + isAvailable: jest.fn(), + } as any, SavedObjectFinder: () => null, ExitFullScreenButton: () => null, - uiActions: {} as any, + uiActions: { + getTriggerCompatibleActions: (() => []) as any, + } as any, }; dashboardContainer = new DashboardContainer(initialInput, options); const defaultTestProps: DashboardGridProps = { @@ -100,12 +104,11 @@ test('renders DashboardGrid', () => { ); - const panelElements = component.find('EmbeddableChildPanel'); expect(panelElements.length).toBe(2); }); -test('renders DashboardGrid with no visualizations', async () => { +test('renders DashboardGrid with no visualizations', () => { const { props, options } = prepare(); const component = mountWithIntl( @@ -114,12 +117,11 @@ test('renders DashboardGrid with no visualizations', async () => { ); props.container.updateInput({ panels: {} }); - await nextTick(); component.update(); expect(component.find('EmbeddableChildPanel').length).toBe(0); }); -test('DashboardGrid removes panel when removed from container', async () => { +test('DashboardGrid removes panel when removed from container', () => { const { props, options } = prepare(); const component = mountWithIntl( @@ -131,13 +133,12 @@ test('DashboardGrid removes panel when removed from container', async () => { const filteredPanels = { ...originalPanels }; delete filteredPanels['1']; props.container.updateInput({ panels: filteredPanels }); - await nextTick(); component.update(); const panelElements = component.find('EmbeddableChildPanel'); expect(panelElements.length).toBe(1); }); -test('DashboardGrid renders expanded panel', async () => { +test('DashboardGrid renders expanded panel', () => { const { props, options } = prepare(); const component = mountWithIntl( @@ -146,7 +147,6 @@ test('DashboardGrid renders expanded panel', async () => { ); props.container.updateInput({ expandedPanelId: '1' }); - await nextTick(); component.update(); // Both panels should still exist in the dom, so nothing needs to be re-fetched once minimized. expect(component.find('EmbeddableChildPanel').length).toBe(2); @@ -156,7 +156,6 @@ test('DashboardGrid renders expanded panel', async () => { ).toBe('1'); props.container.updateInput({ expandedPanelId: undefined }); - await nextTick(); component.update(); expect(component.find('EmbeddableChildPanel').length).toBe(2); diff --git a/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.test.tsx b/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.test.tsx index 7b83407bf806..a2f7b8dc28fb 100644 --- a/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.test.tsx +++ b/src/plugins/dashboard_embeddable_container/public/embeddable/viewport/dashboard_viewport.test.tsx @@ -56,10 +56,14 @@ function getProps( } as any, notifications: {} as any, overlays: {} as any, - inspector: {} as any, + inspector: { + isAvailable: jest.fn(), + } as any, SavedObjectFinder: () => null, ExitFullScreenButton, - uiActions: {} as any, + uiActions: { + getTriggerCompatibleActions: (() => []) as any, + } as any, }; const input = getSampleDashboardInput({ diff --git a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap index 61aac70b4a7e..4a5b0bed5e81 100644 --- a/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap +++ b/src/plugins/data/public/ui/query_string_input/__snapshots__/query_string_input.test.tsx.snap @@ -148,6 +148,74 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA "setIsCollapsed": [MockFunction], "setIsVisible": [MockFunction], }, + "data": Object { + "autocomplete": Object { + "addProvider": [MockFunction], + "clearProviders": [MockFunction], + "getProvider": [MockFunction], + }, + "fieldFormats": Object { + "getByFieldType": [MockFunction], + "getConfig": [MockFunction], + "getDefaultConfig": [MockFunction], + "getDefaultInstance": [MockFunction], + "getDefaultInstanceCacheResolver": [MockFunction], + "getDefaultInstancePlain": [MockFunction], + "getDefaultType": [MockFunction], + "getDefaultTypeName": [MockFunction], + "getInstance": [MockFunction], + "getType": [MockFunction], + "getTypeNameByEsTypes": [MockFunction], + "init": [MockFunction], + "parseDefaultTypeMap": [MockFunction], + "register": [MockFunction], + }, + "getSuggestions": [MockFunction], + "indexPatterns": Object { + "FieldList": Object {}, + "IndexPatternSelect": [MockFunction], + "flattenHitWrapper": [MockFunction], + "formatHitProvider": [MockFunction], + "indexPatterns": [MockFunction], + }, + "query": Object { + "filterManager": [MockFunction], + "savedQueries": [MockFunction], + "timefilter": Object { + "history": Object { + "add": [MockFunction], + "get": [MockFunction], + }, + "timefilter": Object { + "calculateBounds": [MockFunction], + "createFilter": [MockFunction], + "disableAutoRefreshSelector": [MockFunction], + "disableTimeRangeSelector": [MockFunction], + "enableAutoRefreshSelector": [MockFunction], + "enableTimeRangeSelector": [MockFunction], + "getActiveBounds": [MockFunction], + "getAutoRefreshFetch$": [MockFunction], + "getBounds": [MockFunction], + "getEnabledUpdated$": [MockFunction], + "getFetch$": [MockFunction], + "getRefreshInterval": [MockFunction], + "getRefreshIntervalUpdate$": [MockFunction], + "getTime": [MockFunction], + "getTimeUpdate$": [MockFunction], + "isAutoRefreshSelectorEnabled": [MockFunction], + "isTimeRangeSelectorEnabled": [MockFunction], + "setRefreshInterval": [MockFunction], + "setTime": [MockFunction], + }, + }, + }, + "search": Object { + "search": [MockFunction], + }, + "ui": Object { + "IndexPatternSelect": [MockFunction], + }, + }, "docLinks": Object { "DOC_LINK_VERSION": "mocked-test-branch", "ELASTIC_WEBSITE_URL": "https://www.elastic.co/", @@ -710,6 +778,74 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA "setIsCollapsed": [MockFunction], "setIsVisible": [MockFunction], }, + "data": Object { + "autocomplete": Object { + "addProvider": [MockFunction], + "clearProviders": [MockFunction], + "getProvider": [MockFunction], + }, + "fieldFormats": Object { + "getByFieldType": [MockFunction], + "getConfig": [MockFunction], + "getDefaultConfig": [MockFunction], + "getDefaultInstance": [MockFunction], + "getDefaultInstanceCacheResolver": [MockFunction], + "getDefaultInstancePlain": [MockFunction], + "getDefaultType": [MockFunction], + "getDefaultTypeName": [MockFunction], + "getInstance": [MockFunction], + "getType": [MockFunction], + "getTypeNameByEsTypes": [MockFunction], + "init": [MockFunction], + "parseDefaultTypeMap": [MockFunction], + "register": [MockFunction], + }, + "getSuggestions": [MockFunction], + "indexPatterns": Object { + "FieldList": Object {}, + "IndexPatternSelect": [MockFunction], + "flattenHitWrapper": [MockFunction], + "formatHitProvider": [MockFunction], + "indexPatterns": [MockFunction], + }, + "query": Object { + "filterManager": [MockFunction], + "savedQueries": [MockFunction], + "timefilter": Object { + "history": Object { + "add": [MockFunction], + "get": [MockFunction], + }, + "timefilter": Object { + "calculateBounds": [MockFunction], + "createFilter": [MockFunction], + "disableAutoRefreshSelector": [MockFunction], + "disableTimeRangeSelector": [MockFunction], + "enableAutoRefreshSelector": [MockFunction], + "enableTimeRangeSelector": [MockFunction], + "getActiveBounds": [MockFunction], + "getAutoRefreshFetch$": [MockFunction], + "getBounds": [MockFunction], + "getEnabledUpdated$": [MockFunction], + "getFetch$": [MockFunction], + "getRefreshInterval": [MockFunction], + "getRefreshIntervalUpdate$": [MockFunction], + "getTime": [MockFunction], + "getTimeUpdate$": [MockFunction], + "isAutoRefreshSelectorEnabled": [MockFunction], + "isTimeRangeSelectorEnabled": [MockFunction], + "setRefreshInterval": [MockFunction], + "setTime": [MockFunction], + }, + }, + }, + "search": Object { + "search": [MockFunction], + }, + "ui": Object { + "IndexPatternSelect": [MockFunction], + }, + }, "docLinks": Object { "DOC_LINK_VERSION": "mocked-test-branch", "ELASTIC_WEBSITE_URL": "https://www.elastic.co/", @@ -1260,6 +1396,74 @@ exports[`QueryStringInput Should pass the query language to the language switche "setIsCollapsed": [MockFunction], "setIsVisible": [MockFunction], }, + "data": Object { + "autocomplete": Object { + "addProvider": [MockFunction], + "clearProviders": [MockFunction], + "getProvider": [MockFunction], + }, + "fieldFormats": Object { + "getByFieldType": [MockFunction], + "getConfig": [MockFunction], + "getDefaultConfig": [MockFunction], + "getDefaultInstance": [MockFunction], + "getDefaultInstanceCacheResolver": [MockFunction], + "getDefaultInstancePlain": [MockFunction], + "getDefaultType": [MockFunction], + "getDefaultTypeName": [MockFunction], + "getInstance": [MockFunction], + "getType": [MockFunction], + "getTypeNameByEsTypes": [MockFunction], + "init": [MockFunction], + "parseDefaultTypeMap": [MockFunction], + "register": [MockFunction], + }, + "getSuggestions": [MockFunction], + "indexPatterns": Object { + "FieldList": Object {}, + "IndexPatternSelect": [MockFunction], + "flattenHitWrapper": [MockFunction], + "formatHitProvider": [MockFunction], + "indexPatterns": [MockFunction], + }, + "query": Object { + "filterManager": [MockFunction], + "savedQueries": [MockFunction], + "timefilter": Object { + "history": Object { + "add": [MockFunction], + "get": [MockFunction], + }, + "timefilter": Object { + "calculateBounds": [MockFunction], + "createFilter": [MockFunction], + "disableAutoRefreshSelector": [MockFunction], + "disableTimeRangeSelector": [MockFunction], + "enableAutoRefreshSelector": [MockFunction], + "enableTimeRangeSelector": [MockFunction], + "getActiveBounds": [MockFunction], + "getAutoRefreshFetch$": [MockFunction], + "getBounds": [MockFunction], + "getEnabledUpdated$": [MockFunction], + "getFetch$": [MockFunction], + "getRefreshInterval": [MockFunction], + "getRefreshIntervalUpdate$": [MockFunction], + "getTime": [MockFunction], + "getTimeUpdate$": [MockFunction], + "isAutoRefreshSelectorEnabled": [MockFunction], + "isTimeRangeSelectorEnabled": [MockFunction], + "setRefreshInterval": [MockFunction], + "setTime": [MockFunction], + }, + }, + }, + "search": Object { + "search": [MockFunction], + }, + "ui": Object { + "IndexPatternSelect": [MockFunction], + }, + }, "docLinks": Object { "DOC_LINK_VERSION": "mocked-test-branch", "ELASTIC_WEBSITE_URL": "https://www.elastic.co/", @@ -1819,6 +2023,74 @@ exports[`QueryStringInput Should pass the query language to the language switche "setIsCollapsed": [MockFunction], "setIsVisible": [MockFunction], }, + "data": Object { + "autocomplete": Object { + "addProvider": [MockFunction], + "clearProviders": [MockFunction], + "getProvider": [MockFunction], + }, + "fieldFormats": Object { + "getByFieldType": [MockFunction], + "getConfig": [MockFunction], + "getDefaultConfig": [MockFunction], + "getDefaultInstance": [MockFunction], + "getDefaultInstanceCacheResolver": [MockFunction], + "getDefaultInstancePlain": [MockFunction], + "getDefaultType": [MockFunction], + "getDefaultTypeName": [MockFunction], + "getInstance": [MockFunction], + "getType": [MockFunction], + "getTypeNameByEsTypes": [MockFunction], + "init": [MockFunction], + "parseDefaultTypeMap": [MockFunction], + "register": [MockFunction], + }, + "getSuggestions": [MockFunction], + "indexPatterns": Object { + "FieldList": Object {}, + "IndexPatternSelect": [MockFunction], + "flattenHitWrapper": [MockFunction], + "formatHitProvider": [MockFunction], + "indexPatterns": [MockFunction], + }, + "query": Object { + "filterManager": [MockFunction], + "savedQueries": [MockFunction], + "timefilter": Object { + "history": Object { + "add": [MockFunction], + "get": [MockFunction], + }, + "timefilter": Object { + "calculateBounds": [MockFunction], + "createFilter": [MockFunction], + "disableAutoRefreshSelector": [MockFunction], + "disableTimeRangeSelector": [MockFunction], + "enableAutoRefreshSelector": [MockFunction], + "enableTimeRangeSelector": [MockFunction], + "getActiveBounds": [MockFunction], + "getAutoRefreshFetch$": [MockFunction], + "getBounds": [MockFunction], + "getEnabledUpdated$": [MockFunction], + "getFetch$": [MockFunction], + "getRefreshInterval": [MockFunction], + "getRefreshIntervalUpdate$": [MockFunction], + "getTime": [MockFunction], + "getTimeUpdate$": [MockFunction], + "isAutoRefreshSelectorEnabled": [MockFunction], + "isTimeRangeSelectorEnabled": [MockFunction], + "setRefreshInterval": [MockFunction], + "setTime": [MockFunction], + }, + }, + }, + "search": Object { + "search": [MockFunction], + }, + "ui": Object { + "IndexPatternSelect": [MockFunction], + }, + }, "docLinks": Object { "DOC_LINK_VERSION": "mocked-test-branch", "ELASTIC_WEBSITE_URL": "https://www.elastic.co/", @@ -2369,6 +2641,74 @@ exports[`QueryStringInput Should render the given query 1`] = ` "setIsCollapsed": [MockFunction], "setIsVisible": [MockFunction], }, + "data": Object { + "autocomplete": Object { + "addProvider": [MockFunction], + "clearProviders": [MockFunction], + "getProvider": [MockFunction], + }, + "fieldFormats": Object { + "getByFieldType": [MockFunction], + "getConfig": [MockFunction], + "getDefaultConfig": [MockFunction], + "getDefaultInstance": [MockFunction], + "getDefaultInstanceCacheResolver": [MockFunction], + "getDefaultInstancePlain": [MockFunction], + "getDefaultType": [MockFunction], + "getDefaultTypeName": [MockFunction], + "getInstance": [MockFunction], + "getType": [MockFunction], + "getTypeNameByEsTypes": [MockFunction], + "init": [MockFunction], + "parseDefaultTypeMap": [MockFunction], + "register": [MockFunction], + }, + "getSuggestions": [MockFunction], + "indexPatterns": Object { + "FieldList": Object {}, + "IndexPatternSelect": [MockFunction], + "flattenHitWrapper": [MockFunction], + "formatHitProvider": [MockFunction], + "indexPatterns": [MockFunction], + }, + "query": Object { + "filterManager": [MockFunction], + "savedQueries": [MockFunction], + "timefilter": Object { + "history": Object { + "add": [MockFunction], + "get": [MockFunction], + }, + "timefilter": Object { + "calculateBounds": [MockFunction], + "createFilter": [MockFunction], + "disableAutoRefreshSelector": [MockFunction], + "disableTimeRangeSelector": [MockFunction], + "enableAutoRefreshSelector": [MockFunction], + "enableTimeRangeSelector": [MockFunction], + "getActiveBounds": [MockFunction], + "getAutoRefreshFetch$": [MockFunction], + "getBounds": [MockFunction], + "getEnabledUpdated$": [MockFunction], + "getFetch$": [MockFunction], + "getRefreshInterval": [MockFunction], + "getRefreshIntervalUpdate$": [MockFunction], + "getTime": [MockFunction], + "getTimeUpdate$": [MockFunction], + "isAutoRefreshSelectorEnabled": [MockFunction], + "isTimeRangeSelectorEnabled": [MockFunction], + "setRefreshInterval": [MockFunction], + "setTime": [MockFunction], + }, + }, + }, + "search": Object { + "search": [MockFunction], + }, + "ui": Object { + "IndexPatternSelect": [MockFunction], + }, + }, "docLinks": Object { "DOC_LINK_VERSION": "mocked-test-branch", "ELASTIC_WEBSITE_URL": "https://www.elastic.co/", @@ -2928,6 +3268,74 @@ exports[`QueryStringInput Should render the given query 1`] = ` "setIsCollapsed": [MockFunction], "setIsVisible": [MockFunction], }, + "data": Object { + "autocomplete": Object { + "addProvider": [MockFunction], + "clearProviders": [MockFunction], + "getProvider": [MockFunction], + }, + "fieldFormats": Object { + "getByFieldType": [MockFunction], + "getConfig": [MockFunction], + "getDefaultConfig": [MockFunction], + "getDefaultInstance": [MockFunction], + "getDefaultInstanceCacheResolver": [MockFunction], + "getDefaultInstancePlain": [MockFunction], + "getDefaultType": [MockFunction], + "getDefaultTypeName": [MockFunction], + "getInstance": [MockFunction], + "getType": [MockFunction], + "getTypeNameByEsTypes": [MockFunction], + "init": [MockFunction], + "parseDefaultTypeMap": [MockFunction], + "register": [MockFunction], + }, + "getSuggestions": [MockFunction], + "indexPatterns": Object { + "FieldList": Object {}, + "IndexPatternSelect": [MockFunction], + "flattenHitWrapper": [MockFunction], + "formatHitProvider": [MockFunction], + "indexPatterns": [MockFunction], + }, + "query": Object { + "filterManager": [MockFunction], + "savedQueries": [MockFunction], + "timefilter": Object { + "history": Object { + "add": [MockFunction], + "get": [MockFunction], + }, + "timefilter": Object { + "calculateBounds": [MockFunction], + "createFilter": [MockFunction], + "disableAutoRefreshSelector": [MockFunction], + "disableTimeRangeSelector": [MockFunction], + "enableAutoRefreshSelector": [MockFunction], + "enableTimeRangeSelector": [MockFunction], + "getActiveBounds": [MockFunction], + "getAutoRefreshFetch$": [MockFunction], + "getBounds": [MockFunction], + "getEnabledUpdated$": [MockFunction], + "getFetch$": [MockFunction], + "getRefreshInterval": [MockFunction], + "getRefreshIntervalUpdate$": [MockFunction], + "getTime": [MockFunction], + "getTimeUpdate$": [MockFunction], + "isAutoRefreshSelectorEnabled": [MockFunction], + "isTimeRangeSelectorEnabled": [MockFunction], + "setRefreshInterval": [MockFunction], + "setTime": [MockFunction], + }, + }, + }, + "search": Object { + "search": [MockFunction], + }, + "ui": Object { + "IndexPatternSelect": [MockFunction], + }, + }, "docLinks": Object { "DOC_LINK_VERSION": "mocked-test-branch", "ELASTIC_WEBSITE_URL": "https://www.elastic.co/", diff --git a/src/plugins/data/public/ui/query_string_input/query_bar_top_row.test.tsx b/src/plugins/data/public/ui/query_string_input/query_bar_top_row.test.tsx index 51f0abbd102c..70d0c96b4733 100644 --- a/src/plugins/data/public/ui/query_string_input/query_bar_top_row.test.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_bar_top_row.test.tsx @@ -24,6 +24,7 @@ import { mount } from 'enzyme'; import { QueryBarTopRow } from './query_bar_top_row'; import { coreMock } from '../../../../../core/public/mocks'; +import { dataPluginMock } from '../../mocks'; import { KibanaContextProvider } from 'src/plugins/kibana_react/public'; import { I18nProvider } from '@kbn/i18n/react'; import { stubIndexPatternWithFields } from '../../stubs'; @@ -95,6 +96,7 @@ function wrapQueryBarTopRowInContext(testProps: any) { const services = { ...startMock, + data: dataPluginMock.createStartContract(), appName: 'discover', storage: createMockStorage(), }; @@ -117,7 +119,7 @@ describe('QueryBarTopRowTopRow', () => { jest.clearAllMocks(); }); - it('Should render the given query', () => { + it('Should render query and time picker', () => { const component = mount( wrapQueryBarTopRowInContext({ query: kqlQuery, diff --git a/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx b/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx index 3c98ee948c7d..4435bd87cd2d 100644 --- a/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx +++ b/src/plugins/data/public/ui/query_string_input/query_string_input.test.tsx @@ -28,6 +28,7 @@ import React from 'react'; import { QueryLanguageSwitcher } from './language_switcher'; import { QueryStringInput, QueryStringInputUI } from './query_string_input'; import { coreMock } from '../../../../../core/public/mocks'; +import { dataPluginMock } from '../../mocks'; const startMock = coreMock.createStart(); import { stubIndexPatternWithFields } from '../../stubs'; @@ -74,6 +75,7 @@ function wrapQueryStringInputInContext(testProps: any, storage?: any) { const services = { ...startMock, + data: dataPluginMock.createStartContract(), appName: testProps.appName || 'test', storage: storage || createMockStorage(), }; diff --git a/src/plugins/kibana_react/public/saved_objects/saved_object_finder.test.tsx b/src/plugins/kibana_react/public/saved_objects/saved_object_finder.test.tsx index 5b3d638f9e93..b35ba427378a 100644 --- a/src/plugins/kibana_react/public/saved_objects/saved_object_finder.test.tsx +++ b/src/plugins/kibana_react/public/saved_objects/saved_object_finder.test.tsx @@ -251,6 +251,7 @@ describe('SavedObjectsFinder', () => { it('should include additional fields in search if listed in meta data', async () => { const core = coreMock.createStart(); core.uiSettings.get.mockImplementation(() => 10); + (core.savedObjects.client.find as jest.Mock).mockResolvedValue({ savedObjects: [] }); const wrapper = shallow( { describe('loading state', () => { it('should display a spinner during initial loading', () => { const core = coreMock.createStart(); + (core.savedObjects.client.find as jest.Mock).mockResolvedValue({ savedObjects: [] }); const wrapper = shallow( { - imageDiff.getFullResult({ - actualImage: sessionImagePath, - expectedImage: baselineImagePath, - diffImage: diffImagePath, - shadow: true, - }, cb); - }); + const sessionImage = PNG.sync.read(await fs.promises.readFile(sessionImagePath)); + const baselineImage = PNG.sync.read(await fs.promises.readFile(baselineImagePath)); + const { width, height } = sessionImage; + const diff = new PNG({ width, height }); - const change = diffResult.percentage; + const numDiffPixels = pixelmatch( + sessionImage.data, + baselineImage.data, + diff.data, + width, + height, + { threshold: 0 } + ); + + await fs.promises.writeFile(diffImagePath, PNG.sync.write(diff)); + + const change = numDiffPixels / (width * height); const changePercentage = (change * 100).toFixed(2); console.log(`(${changePercentage}%) ${screenshot}`); comparison.percentage = changePercentage; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts index f05d343ad7ba..de423e967b0b 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts +++ b/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts @@ -27,7 +27,7 @@ describe('createErrorGroupWatch', () => { .mockResolvedValue(undefined); beforeEach(async () => { - jest.spyOn(uuid, 'v4').mockReturnValue(new Buffer('mocked-uuid')); + jest.spyOn(uuid, 'v4').mockReturnValue(Buffer.from('mocked-uuid')); createWatchResponse = await createErrorGroupWatch({ http: {} as HttpServiceBase, diff --git a/x-pack/legacy/plugins/index_management/__mocks__/ui/notify.js b/x-pack/legacy/plugins/index_management/__mocks__/ui/notify.js index 27d24efb79c9..d508c3383d5f 100644 --- a/x-pack/legacy/plugins/index_management/__mocks__/ui/notify.js +++ b/x-pack/legacy/plugins/index_management/__mocks__/ui/notify.js @@ -10,3 +10,5 @@ export const toastNotifications = { addWarning: () => {}, addError: () => {}, }; + +export function fatalError() {} diff --git a/x-pack/legacy/plugins/reporting/public/components/report_info_button.tsx b/x-pack/legacy/plugins/reporting/public/components/report_info_button.tsx index 52dd1071deaa..77869c40d357 100644 --- a/x-pack/legacy/plugins/reporting/public/components/report_info_button.tsx +++ b/x-pack/legacy/plugins/reporting/public/components/report_info_button.tsx @@ -266,7 +266,6 @@ export class ReportInfoButton extends Component { info: null, error: kfetchError, }); - throw kfetchError; } } }; diff --git a/x-pack/legacy/plugins/reporting/server/lib/esqueue/__tests__/worker.js b/x-pack/legacy/plugins/reporting/server/lib/esqueue/__tests__/worker.js index 9d3e1874d103..051178ebcc91 100644 --- a/x-pack/legacy/plugins/reporting/server/lib/esqueue/__tests__/worker.js +++ b/x-pack/legacy/plugins/reporting/server/lib/esqueue/__tests__/worker.js @@ -246,7 +246,9 @@ describe('Worker class', function () { it('should use error multiplier when processPendingJobs rejects the Promise', async function () { worker = new Worker(mockQueue, 'test', noop, defaultWorkerOptions); - const processPendingJobsStub = sinon.stub(worker, '_processPendingJobs').returns(Promise.reject(new Error('test error'))); + const processPendingJobsStub = sinon + .stub(worker, '_processPendingJobs') + .rejects(new Error('test error')); await allowPoll(defaultWorkerOptions.interval); expect(processPendingJobsStub.callCount).to.be(1); @@ -517,7 +519,7 @@ describe('Worker class', function () { it('should emit for errors from claiming job', function (done) { sinon.stub(mockQueue.client, 'callWithInternalUser') .withArgs('update') - .returns(Promise.reject({ statusCode: 401 })); + .rejects({ statusCode: 401 }); worker.once(constants.EVENT_WORKER_JOB_CLAIM_ERROR, function (err) { try { @@ -531,13 +533,13 @@ describe('Worker class', function () { } }); - worker._claimPendingJobs(getMockJobs()); + worker._claimPendingJobs(getMockJobs()).catch(() => {}); }); it('should reject the promise if an error claiming the job', function () { sinon.stub(mockQueue.client, 'callWithInternalUser') .withArgs('update') - .returns(Promise.reject({ statusCode: 409 })); + .rejects({ statusCode: 409 }); return worker._claimPendingJobs(getMockJobs()) .catch(err => { expect(err).to.eql({ statusCode: 409 }); @@ -547,7 +549,7 @@ describe('Worker class', function () { it('should get the pending job', function () { sinon.stub(mockQueue.client, 'callWithInternalUser') .withArgs('update') - .returns(Promise.resolve({ test: 'cool' })); + .resolves({ test: 'cool' }); sinon.stub(worker, '_performJob').callsFake(identity); return worker._claimPendingJobs(getMockJobs()) .then(claimedJob => { @@ -607,7 +609,7 @@ describe('Worker class', function () { mockQueue.client.callWithInternalUser.restore(); sinon.stub(mockQueue.client, 'callWithInternalUser') .withArgs('update') - .returns(Promise.reject({ statusCode: 409 })); + .rejects({ statusCode: 409 }); return worker._failJob(job) .then((res) => expect(res).to.equal(true)); }); @@ -616,7 +618,7 @@ describe('Worker class', function () { mockQueue.client.callWithInternalUser.restore(); sinon.stub(mockQueue.client, 'callWithInternalUser') .withArgs('update') - .returns(Promise.reject({ statusCode: 401 })); + .rejects({ statusCode: 401 }); return worker._failJob(job) .then((res) => expect(res).to.equal(false)); }); @@ -654,7 +656,7 @@ describe('Worker class', function () { mockQueue.client.callWithInternalUser.restore(); sinon.stub(mockQueue.client, 'callWithInternalUser') .withArgs('update') - .returns(Promise.reject({ statusCode: 401 })); + .rejects({ statusCode: 401 }); worker.on(constants.EVENT_WORKER_FAIL_UPDATE_ERROR, function (err) { try { @@ -842,7 +844,7 @@ describe('Worker class', function () { describe('job failures', function () { function getFailStub(workerWithFailure) { - return sinon.stub(workerWithFailure, '_failJob').returns(Promise.resolve()); + return sinon.stub(workerWithFailure, '_failJob').resolves(); } describe('saving output failure', () => { @@ -857,7 +859,7 @@ describe('Worker class', function () { sinon.stub(mockQueue.client, 'callWithInternalUser') .withArgs('update') - .returns(Promise.reject({ statusCode: 413 })); + .rejects({ statusCode: 413 }); const workerFn = function (jobPayload) { return new Promise(function (resolve) { @@ -878,7 +880,7 @@ describe('Worker class', function () { it('causes _processPendingJobs to reject the Promise', function () { sinon.stub(mockQueue.client, 'callWithInternalUser') .withArgs('search') - .returns(Promise.reject(new Error('test error'))); + .rejects(new Error('test error')); worker = new Worker(mockQueue, 'test', noop, defaultWorkerOptions); return worker._processPendingJobs() .then(() => { diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/__snapshots__/index_privileges.test.tsx.snap b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/__snapshots__/index_privileges.test.tsx.snap index 943c3e1518ca..1c4e553daa96 100644 --- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/__snapshots__/index_privileges.test.tsx.snap +++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/__snapshots__/index_privileges.test.tsx.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`it renders without crashing 1`] = `null`; +exports[`it renders without crashing 1`] = ``; diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privileges.test.tsx b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privileges.test.tsx index fbfb9460ecaa..783d2f9893b4 100644 --- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privileges.test.tsx +++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privileges.test.tsx @@ -10,31 +10,36 @@ import { RoleValidator } from '../../../lib/validate_role'; import { IndexPrivilegeForm } from './index_privilege_form'; import { IndexPrivileges } from './index_privileges'; -test('it renders without crashing', () => { +// the IndexPrivileges post-mount hook kicks off some promises; +// we need to wait for those promises to resolve to ensure any errors are properly caught +const flushPromises = () => new Promise(setImmediate); + +test('it renders without crashing', async () => { const props = { role: { name: '', + kibana: [], elasticsearch: { cluster: [], indices: [], run_as: [], }, - kibana: [], }, httpClient: jest.fn(), onChange: jest.fn(), indexPatterns: [], + editable: true, allowDocumentLevelSecurity: true, allowFieldLevelSecurity: true, - editable: true, validator: new RoleValidator(), availableIndexPrivileges: ['all', 'read', 'write', 'index'], }; const wrapper = shallowWithIntl(); + await flushPromises(); expect(wrapper).toMatchSnapshot(); }); -test('it renders a IndexPrivilegeForm for each privilege on the role', () => { +test('it renders a IndexPrivilegeForm for each privilege on the role', async () => { const props = { role: { name: '', @@ -64,5 +69,6 @@ test('it renders a IndexPrivilegeForm for each privilege on the role', () => { availableIndexPrivileges: ['all', 'read', 'write', 'index'], }; const wrapper = mountWithIntl(); + await flushPromises(); expect(wrapper.find(IndexPrivilegeForm)).toHaveLength(1); }); diff --git a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privileges.tsx b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privileges.tsx index 1f54a5aacf94..f09084ad2bb3 100644 --- a/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privileges.tsx +++ b/x-pack/legacy/plugins/security/public/views/management/edit_role/components/privileges/es/index_privileges.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import _ from 'lodash'; -import React, { Component } from 'react'; +import React, { Component, Fragment } from 'react'; import { Role, RoleIndexPrivilege } from '../../../../../../../common/model'; import { isReadOnlyRole, isRoleEnabled } from '../../../../../../lib/role_utils'; import { getFields } from '../../../../../../objects'; @@ -74,7 +74,7 @@ export class IndexPrivileges extends Component { /> )); - return forms; + return {forms}; } public addIndexPrivilege = () => { diff --git a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/__tests__/get_xpack.js b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/__tests__/get_xpack.js index 7a11497c1071..86d7374a8f0d 100644 --- a/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/__tests__/get_xpack.js +++ b/x-pack/legacy/plugins/xpack_main/server/telemetry_collection/__tests__/get_xpack.js @@ -23,7 +23,12 @@ function mockGetXPackLicense(callCluster, license, req) { local: 'true' } }) - .returns(license.then(response => ({ license: response }))); + .returns( + license.then( + response => ({ license: response }), + () => {} // Catch error so that we don't emit UnhandledPromiseRejectionWarning for tests with invalid license + ) + ); callCluster.withArgs('transport.request', { method: 'GET', @@ -33,7 +38,12 @@ function mockGetXPackLicense(callCluster, license, req) { } }) // conveniently wraps the passed in license object as { license: response }, like it really is - .returns(license.then(response => ({ license: response }))); + .returns( + license.then( + response => ({ license: response }), + () => {} // Catch error so that we don't emit UnhandledPromiseRejectionWarning for tests with invalid license + ) + ); } function mockGetXPackUsage(callCluster, usage, req) { diff --git a/x-pack/package.json b/x-pack/package.json index 8dec5418c4d3..e32b0793bad6 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -151,7 +151,7 @@ "null-loader": "^3.0.0", "pdf-image": "2.0.0", "pdfjs-dist": "^2.0.943", - "pixelmatch": "4.0.2", + "pixelmatch": "^5.1.0", "proxyquire": "1.8.0", "react-docgen-typescript-loader": "^3.1.1", "react-test-renderer": "^16.12.0", diff --git a/x-pack/plugins/security/server/authentication/authenticator.test.ts b/x-pack/plugins/security/server/authentication/authenticator.test.ts index d87ed2100101..4ab20f12f363 100644 --- a/x-pack/plugins/security/server/authentication/authenticator.test.ts +++ b/x-pack/plugins/security/server/authentication/authenticator.test.ts @@ -516,16 +516,19 @@ describe('Authenticator', () => { expect(mockSessionStorage.clear).not.toHaveBeenCalled(); }); - it('only updates the session lifespan expiration if it does not match the current server config.', async () => { - const user = mockAuthenticatedUser(); - const request = httpServerMock.createKibanaRequest(); + describe('conditionally updates the session lifespan expiration', () => { const hr = 1000 * 60 * 60; + const currentDate = new Date(Date.UTC(2019, 10, 10)).valueOf(); async function createAndUpdateSession( lifespan: number | null, oldExpiration: number | null, newExpiration: number | null ) { + const user = mockAuthenticatedUser(); + const request = httpServerMock.createKibanaRequest(); + jest.spyOn(Date, 'now').mockImplementation(() => currentDate); + mockOptions = getMockOptions({ session: { idleTimeout: null, @@ -537,7 +540,7 @@ describe('Authenticator', () => { mockSessionStorage = sessionStorageMock.create(); mockSessionStorage.get.mockResolvedValue({ ...mockSessVal, - idleTimeoutExpiration: 1, + idleTimeoutExpiration: null, lifespanExpiration: oldExpiration, }); mockOptions.sessionStorageFactory.asScoped.mockReturnValue(mockSessionStorage); @@ -555,17 +558,24 @@ describe('Authenticator', () => { expect(mockSessionStorage.set).toHaveBeenCalledTimes(1); expect(mockSessionStorage.set).toHaveBeenCalledWith({ ...mockSessVal, - idleTimeoutExpiration: 1, + idleTimeoutExpiration: null, lifespanExpiration: newExpiration, }); expect(mockSessionStorage.clear).not.toHaveBeenCalled(); } - // do not change max expiration - createAndUpdateSession(hr * 8, 1234, 1234); - createAndUpdateSession(null, null, null); - // change max expiration - createAndUpdateSession(null, 1234, null); - createAndUpdateSession(hr * 8, null, hr * 8); + + it('does not change a non-null lifespan expiration when configured to non-null value.', async () => { + await createAndUpdateSession(hr * 8, 1234, 1234); + }); + it('does not change a null lifespan expiration when configured to null value.', async () => { + await createAndUpdateSession(null, null, null); + }); + it('does change a non-null lifespan expiration when configured to null value.', async () => { + await createAndUpdateSession(null, 1234, null); + }); + it('does change a null lifespan expiration when configured to non-null value', async () => { + await createAndUpdateSession(hr * 8, null, currentDate + hr * 8); + }); }); it('does not touch session for system API calls if authentication fails with non-401 reason.', async () => { diff --git a/yarn.lock b/yarn.lock index b8c5ffb287b3..d61ae67ff064 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5495,21 +5495,11 @@ array-map@~0.0.0: resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" integrity sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI= -array-parallel@~0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/array-parallel/-/array-parallel-0.1.3.tgz#8f785308926ed5aa478c47e64d1b334b6c0c947d" - integrity sha1-j3hTCJJu1apHjEfmTRszS2wMlH0= - array-reduce@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" integrity sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys= -array-series@~0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/array-series/-/array-series-0.1.5.tgz#df5d37bfc5c2ef0755e2aa4f92feae7d4b5a972f" - integrity sha1-3103v8XC7wdV4qpPkv6ufUtaly8= - array-slice@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" @@ -5785,11 +5775,6 @@ async@^2.6.3: dependencies: lodash "^4.17.14" -async@~0.2.9: - version "0.2.10" - resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" - integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E= - async@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9" @@ -7100,15 +7085,6 @@ buffer@^5.1.0, buffer@^5.2.0: base64-js "^1.0.2" ieee754 "^1.1.4" -buffered-spawn@~1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffered-spawn/-/buffered-spawn-1.1.2.tgz#21ad9735dfbf6576745be0d74a23ef257bf3c58d" - integrity sha1-Ia2XNd+/ZXZ0W+DXSiPvJXvzxY0= - dependencies: - cross-spawn-async "^1.0.1" - err-code "^0.1.0" - q "^1.0.1" - builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -8345,13 +8321,6 @@ commander@~2.8.1: dependencies: graceful-readlink ">= 1.0.0" -commander@~2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" - integrity sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q= - dependencies: - graceful-readlink ">= 1.0.0" - common-tags@1.8.0, common-tags@^1.8.0: version "1.8.0" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" @@ -8935,14 +8904,6 @@ cross-fetch@2.2.2: node-fetch "2.1.2" whatwg-fetch "2.0.4" -cross-spawn-async@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cross-spawn-async/-/cross-spawn-async-1.0.1.tgz#bb525c1e420d9942552e04791a3eb2d9887a105f" - integrity sha1-u1JcHkINmUJVLgR5Gj6y2Yh6EF8= - dependencies: - lru-cache "^2.6.5" - which "^1.1.1" - cross-spawn-async@^2.1.1: version "2.2.5" resolved "https://registry.yarnpkg.com/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz#845ff0c0834a3ded9d160daca6d390906bb288cc" @@ -9679,7 +9640,7 @@ debug-fabulous@1.X: memoizee "0.4.X" object-assign "4.X" -debug@2.6.9, debug@^2.0.0, debug@^2.1.0, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9, debug@~2.2.0: +debug@2.6.9, debug@^2.0.0, debug@^2.1.0, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -10968,11 +10929,6 @@ enzyme@^3.10.0: rst-selector-parser "^2.2.3" string.prototype.trim "^1.1.2" -err-code@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-0.1.2.tgz#122a92b3342b9899da02b5ac994d30f95d4763ee" - integrity sha1-EiqSszQrmJnaArWsmU0w+V1HY+4= - errlop@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/errlop/-/errlop-1.1.2.tgz#a99a48f37aa264d614e342ffdbbaa49eec9220e0" @@ -13809,15 +13765,6 @@ glogg@^1.0.0: dependencies: sparkles "^1.0.0" -gm@~1.21.1: - version "1.21.1" - resolved "https://registry.yarnpkg.com/gm/-/gm-1.21.1.tgz#7ed5ed05db36d30c1943f39c3bc1c839b8f2361d" - integrity sha1-ftXtBds20wwZQ/OcO8HIObjyNh0= - dependencies: - array-parallel "~0.1.3" - array-series "~0.1.5" - debug "~2.2.0" - gonzales-pe-sl@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/gonzales-pe-sl/-/gonzales-pe-sl-4.2.3.tgz#6a868bc380645f141feeb042c6f97fcc71b59fe6" @@ -15276,18 +15223,6 @@ ignore@^5.1.1: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.2.tgz#e28e584d43ad7e92f96995019cc43b9e1ac49558" integrity sha512-vdqWBp7MyzdmHkkRWV5nY+PfGRbYbahfuvsBCh277tq+w9zyNi7h5CYJCK0kmzti9kU+O/cB7sE8HvKv6aXAKQ== -image-diff@1.6.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/image-diff/-/image-diff-1.6.3.tgz#818a0e656ae89480e802e7ef14db460826f730fc" - integrity sha1-gYoOZWrolIDoAufvFNtGCCb3MPw= - dependencies: - async "~0.2.9" - buffered-spawn "~1.1.1" - commander "~2.9.0" - gm "~1.21.1" - mkdirp "~0.3.5" - tmp "0.0.23" - image-size@~0.5.0: version "0.5.5" resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" @@ -18713,11 +18648,6 @@ lru-cache@4.1.x, lru-cache@^4.0.0: pseudomap "^1.0.2" yallist "^2.1.2" -lru-cache@^2.6.5: - version "2.7.3" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" - integrity sha1-bUUk6LlV+V1PW1iFHOId1y+06VI= - lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -19552,7 +19482,7 @@ mixin-object@^2.0.1: for-in "^0.1.3" is-extendable "^0.1.1" -mkdirp@0.3.5, mkdirp@^0.3.5, mkdirp@~0.3.5: +mkdirp@0.3.5, mkdirp@^0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" integrity sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc= @@ -21797,13 +21727,20 @@ pirates@^4.0.0, pirates@^4.0.1: dependencies: node-modules-regexp "^1.0.0" -pixelmatch@4.0.2, pixelmatch@^4.0.2: +pixelmatch@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-4.0.2.tgz#8f47dcec5011b477b67db03c243bc1f3085e8854" integrity sha1-j0fc7FARtHe2fbA8JDvB8wheiFQ= dependencies: pngjs "^3.0.0" +pixelmatch@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-5.1.0.tgz#b640f0e5a03a09f235a4b818ef3b9b98d9d0b911" + integrity sha512-HqtgvuWN12tBzKJf7jYsc38Ha28Q2NYpmBL9WostEGgDHJqbTLkjydZXL1ZHM02ZnB+Dkwlxo87HBY38kMiD6A== + dependencies: + pngjs "^3.4.0" + pkg-dir@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" @@ -22605,7 +22542,7 @@ puppeteer@^1.13.0: rimraf "^2.6.1" ws "^6.1.0" -q@^1.0.1, q@^1.1.2: +q@^1.1.2: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= @@ -27422,11 +27359,6 @@ titleize@^1.0.1: resolved "https://registry.yarnpkg.com/titleize/-/titleize-1.0.1.tgz#21bc24fcca658eadc6d3bd3c38f2bd173769b4c5" integrity sha512-rUwGDruKq1gX+FFHbTl5qjI7teVO7eOe+C8IcQ7QT+1BK3eEUXJqbZcBOeaRP4FwSC/C1A5jDoIVta0nIQ9yew== -tmp@0.0.23: - version "0.0.23" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.23.tgz#de874aa5e974a85f0a32cdfdbd74663cb3bd9c74" - integrity sha1-3odKpel0qF8KMs39vXRmPLO9nHQ= - tmp@0.0.30: version "0.0.30" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed"