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.
This commit is contained in:
Thomas Watson 2019-12-04 18:18:38 +01:00 committed by GitHub
parent dfc0612f26
commit 995a914f63
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 638 additions and 207 deletions

View file

@ -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", "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", "checkLicenses": "node scripts/check_licenses --dev",
"build": "node scripts/build --all-platforms", "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": "node --nolazy --inspect scripts/kibana --dev",
"debug-break": "node --nolazy --inspect-brk scripts/kibana --dev", "debug-break": "node --nolazy --inspect-brk scripts/kibana --dev",
"karma": "karma start", "karma": "karma start",
@ -401,7 +401,6 @@
"gulp-sourcemaps": "2.6.5", "gulp-sourcemaps": "2.6.5",
"has-ansi": "^3.0.0", "has-ansi": "^3.0.0",
"iedriver": "^3.14.1", "iedriver": "^3.14.1",
"image-diff": "1.6.3",
"intl-messageformat-parser": "^1.4.0", "intl-messageformat-parser": "^1.4.0",
"is-path-inside": "^2.1.0", "is-path-inside": "^2.1.0",
"istanbul-instrumenter-loader": "3.0.1", "istanbul-instrumenter-loader": "3.0.1",
@ -429,7 +428,7 @@
"node-sass": "^4.9.4", "node-sass": "^4.9.4",
"normalize-path": "^3.0.0", "normalize-path": "^3.0.0",
"nyc": "^14.1.1", "nyc": "^14.1.1",
"pixelmatch": "4.0.2", "pixelmatch": "^5.1.0",
"pkg-up": "^2.0.0", "pkg-up": "^2.0.0",
"pngjs": "^3.4.0", "pngjs": "^3.4.0",
"postcss": "^7.0.5", "postcss": "^7.0.5",

View file

@ -20,6 +20,7 @@
import { canRequire } from './can_require'; import { canRequire } from './can_require';
import { dependenciesVisitorsGenerator } from './visitors'; import { dependenciesVisitorsGenerator } from './visitors';
import { dirname, isAbsolute, resolve } from 'path'; import { dirname, isAbsolute, resolve } from 'path';
import { builtinModules } from 'module';
export function _calculateTopLevelDependency(inputDep, outputDep = '') { export function _calculateTopLevelDependency(inputDep, outputDep = '') {
// The path separator will be always the forward slash // The path separator will be always the forward slash
@ -48,14 +49,18 @@ export function _calculateTopLevelDependency(inputDep, outputDep = '') {
return _calculateTopLevelDependency(depSplitPaths.join(pathSeparator), outputDep); return _calculateTopLevelDependency(depSplitPaths.join(pathSeparator), outputDep);
} }
export async function dependenciesParseStrategy(cwd, parseSingleFile, mainEntry, wasParsed, results) { export async function dependenciesParseStrategy(
// Retrieve native nodeJS modules cwd,
const natives = process.binding('natives'); parseSingleFile,
mainEntry,
wasParsed,
results
) {
// Get dependencies from a single file and filter // Get dependencies from a single file and filter
// out node native modules from the result // out node native modules from the result
const dependencies = (await parseSingleFile(mainEntry, dependenciesVisitorsGenerator)) const dependencies = (await parseSingleFile(mainEntry, dependenciesVisitorsGenerator)).filter(
.filter(dep => !natives[dep]); dep => !builtinModules.includes(dep)
);
// Return the list of all the new entries found into // Return the list of all the new entries found into
// the current mainEntry that we could use to look for // the current mainEntry that we could use to look for

View file

@ -41,19 +41,9 @@ module.exports = function rewritePackage(buildSource, buildVersion, kibanaVersio
delete pkg.scripts; delete pkg.scripts;
delete pkg.devDependencies; delete pkg.devDependencies;
file.contents = toBuffer(JSON.stringify(pkg, null, 2)); file.contents = Buffer.from(JSON.stringify(pkg, null, 2));
} }
return file; 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');
}
}

View file

@ -329,7 +329,7 @@ describe('Response factory', () => {
const router = createRouter('/'); const router = createRouter('/');
router.get({ path: '/', validate: false }, (context, req, res) => { router.get({ path: '/', validate: false }, (context, req, res) => {
const buffer = new Buffer('abc'); const buffer = Buffer.from('abc');
return res.ok({ return res.ok({
body: buffer, body: buffer,

View file

@ -14,6 +14,8 @@ cacheDir="$HOME/.kibana"
RED='\033[0;31m' RED='\033[0;31m'
C_RESET='\033[0m' # Reset color 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 ### Since the Jenkins logging output collector doesn't look like a TTY
### Node/Chalk and other color libs disable their color output. But Jenkins ### Node/Chalk and other color libs disable their color output. But Jenkins

View file

@ -28,7 +28,7 @@ import { ProxyConfigCollection } from '../proxy_config_collection';
describe('ProxyConfigCollection', function () { describe('ProxyConfigCollection', function () {
beforeEach(function () { beforeEach(function () {
sinon.stub(fs, 'readFileSync').callsFake(() => new Buffer(0)); sinon.stub(fs, 'readFileSync').callsFake(() => Buffer.alloc(0));
}); });
afterEach(function () { afterEach(function () {

View file

@ -43,6 +43,7 @@ const indexPatternsService = {
make: async () => ({ make: async () => ({
fieldsFetcher: { fieldsFetcher: {
fetch: noop, fetch: noop,
fetchForWildcard: noop,
}, },
}), }),
}; };

View file

@ -75,7 +75,7 @@ describe('telemetry_usage_collector', () => {
// empty // empty
writeFileSync(tempFiles.empty, ''); writeFileSync(tempFiles.empty, '');
// 1 byte too big // 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 // write-only file
writeFileSync(tempFiles.unreadable, 'valid: true', { mode: 0o222 }); writeFileSync(tempFiles.unreadable, 'valid: true', { mode: 0o222 });
// valid // valid

View file

@ -95,16 +95,16 @@ describe('yaxis.js', () => {
it('throws an error if currency is not three letter code', () => { it('throws an error if currency is not three letter code', () => {
invoke(fn, [seriesList, 1, null, null, null, null, null, 'currency:abcde']).catch(e => { 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 => { 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 => { 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 => { 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);
}); });
}); });

View file

@ -30,7 +30,7 @@ import { PUBLIC_PATH_PLACEHOLDER } from '../../../optimize/public_path_placehold
const renderSass = promisify(sass.render); const renderSass = promisify(sass.render);
const writeFile = promisify(fs.writeFile); const writeFile = promisify(fs.writeFile);
const exists = promisify(fs.exists); const access = promisify(fs.access);
const copyFile = promisify(fs.copyFile); const copyFile = promisify(fs.copyFile);
const mkdirAsync = promisify(fs.mkdir); const mkdirAsync = promisify(fs.mkdir);
@ -145,23 +145,27 @@ export class Build {
]; ];
// verify that asset sources exist and import is valid before writing anything // verify that asset sources exist and import is valid before writing anything
await Promise.all(urlAssets.map(async (asset) => { await Promise.all(
if (!await exists(asset.path)) { urlAssets.map(async asset => {
throw this._makeError( try {
'Invalid url() in css output', await access(asset.path);
`url("${asset.requestUrl}") resolves to "${asset.path}", which does not exist.\n` + } catch (e) {
` Make sure that the request is relative to "${asset.root}"` 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)) { if (!isPathInside(asset.path, asset.boundry)) {
throw this._makeError( throw this._makeError(
'Invalid url() in css output', 'Invalid url() in css output',
`url("${asset.requestUrl}") resolves to "${asset.path}"\n` + `url("${asset.requestUrl}") resolves to "${asset.path}"\n` +
` which is outside of "${asset.boundry}"` ` which is outside of "${asset.boundry}"`
); );
} }
})); })
);
// write css // write css
await mkdirAsync(this.targetDir, { recursive: true }); await mkdirAsync(this.targetDir, { recursive: true });

View file

@ -40,3 +40,53 @@ const chrome = {
// eslint-disable-next-line import/no-default-export // eslint-disable-next-line import/no-default-export
export default chrome; 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;
});
};

View file

@ -52,7 +52,7 @@ describe('deepCloneWithBuffers()', () => {
}); });
it('copies buffers but keeps them buffers', () => { 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); const output = deepCloneWithBuffers(input);
expect(Buffer.isBuffer(input)).toBe(true); expect(Buffer.isBuffer(input)).toBe(true);
@ -65,7 +65,7 @@ describe('deepCloneWithBuffers()', () => {
const input = { const input = {
a: { a: {
b: { b: {
c: new Buffer('i am a teapot', 'utf8'), c: Buffer.from('i am a teapot', 'utf8'),
}, },
}, },
}; };

View file

@ -24,7 +24,7 @@ import { cloneDeep } from 'lodash';
// type of the customizer function doesn't expect that. // type of the customizer function doesn't expect that.
function cloneBuffersCustomizer(val: unknown): any { function cloneBuffersCustomizer(val: unknown): any {
if (Buffer.isBuffer(val)) { if (Buffer.isBuffer(val)) {
return new Buffer(val); return Buffer.from(val);
} }
} }

View file

@ -29,7 +29,7 @@ import del from 'del';
const readFileAsync = promisify(fs.readFile); const readFileAsync = promisify(fs.readFile);
const mkdirAsync = promisify(fs.mkdir); const mkdirAsync = promisify(fs.mkdir);
const existsAsync = promisify(fs.exists); const accessAsync = promisify(fs.access);
const writeFileAsync = promisify(fs.writeFile); const writeFileAsync = promisify(fs.writeFile);
export class DllCompiler { export class DllCompiler {
@ -127,13 +127,14 @@ export class DllCompiler {
} }
async ensurePathExists(filePath) { async ensurePathExists(filePath) {
const exists = await existsAsync(filePath); try {
await accessAsync(filePath);
if (!exists) { } catch (e) {
await mkdirAsync(path.dirname(filePath), { recursive: true }); await mkdirAsync(path.dirname(filePath), { recursive: true });
return false;
} }
return exists; return true;
} }
async ensureOutputPathExists() { async ensureOutputPathExists() {

View file

@ -16,7 +16,6 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
import { isErrorEmbeddable, EmbeddableFactory } from '../embeddable_plugin'; import { isErrorEmbeddable, EmbeddableFactory } from '../embeddable_plugin';
import { ReplacePanelAction } from './replace_panel_action'; import { ReplacePanelAction } from './replace_panel_action';
import { DashboardContainer } from '../embeddable'; import { DashboardContainer } from '../embeddable';
@ -29,6 +28,8 @@ import {
ContactCardEmbeddableOutput, ContactCardEmbeddableOutput,
} from '../embeddable_plugin_test_samples'; } from '../embeddable_plugin_test_samples';
import { DashboardOptions } from '../embeddable/dashboard_container_factory'; import { DashboardOptions } from '../embeddable/dashboard_container_factory';
import { coreMock } from '../../../../core/public/mocks';
import { CoreStart } from 'kibana/public';
const embeddableFactories = new Map<string, EmbeddableFactory>(); const embeddableFactories = new Map<string, EmbeddableFactory>();
embeddableFactories.set( embeddableFactories.set(
@ -39,8 +40,9 @@ const getEmbeddableFactories = () => embeddableFactories.values();
let container: DashboardContainer; let container: DashboardContainer;
let embeddable: ContactCardEmbeddable; let embeddable: ContactCardEmbeddable;
let coreStart: CoreStart;
beforeEach(async () => { beforeEach(async () => {
coreStart = coreMock.createStart();
const options: DashboardOptions = { const options: DashboardOptions = {
ExitFullScreenButton: () => null, ExitFullScreenButton: () => null,
SavedObjectFinder: () => null, SavedObjectFinder: () => null,
@ -50,7 +52,7 @@ beforeEach(async () => {
} as any, } as any,
inspector: {} as any, inspector: {} as any,
notifications: {} as any, notifications: {} as any,
overlays: {} as any, overlays: coreStart.overlays,
savedObjectMetaData: {} as any, savedObjectMetaData: {} as any,
uiActions: {} as any, uiActions: {} as any,
}; };
@ -80,11 +82,10 @@ beforeEach(async () => {
}); });
test('Executes the replace panel action', async () => { test('Executes the replace panel action', async () => {
let core: any;
let SavedObjectFinder: any; let SavedObjectFinder: any;
let notifications: any; let notifications: any;
const action = new ReplacePanelAction( const action = new ReplacePanelAction(
core, coreStart,
SavedObjectFinder, SavedObjectFinder,
notifications, notifications,
getEmbeddableFactories 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 () => { test('Is not compatible when embeddable is not in a dashboard container', async () => {
let core: any;
let SavedObjectFinder: any; let SavedObjectFinder: any;
let notifications: any; let notifications: any;
const action = new ReplacePanelAction( const action = new ReplacePanelAction(
core, coreStart,
SavedObjectFinder, SavedObjectFinder,
notifications, notifications,
getEmbeddableFactories 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 () => { test('Execute throws an error when called with an embeddable not in a parent', async () => {
let core: any;
let SavedObjectFinder: any; let SavedObjectFinder: any;
let notifications: any; let notifications: any;
const action = new ReplacePanelAction( const action = new ReplacePanelAction(
core, coreStart,
SavedObjectFinder, SavedObjectFinder,
notifications, notifications,
getEmbeddableFactories getEmbeddableFactories
@ -129,11 +128,10 @@ test('Execute throws an error when called with an embeddable not in a parent', a
}); });
test('Returns title', async () => { test('Returns title', async () => {
let core: any;
let SavedObjectFinder: any; let SavedObjectFinder: any;
let notifications: any; let notifications: any;
const action = new ReplacePanelAction( const action = new ReplacePanelAction(
core, coreStart,
SavedObjectFinder, SavedObjectFinder,
notifications, notifications,
getEmbeddableFactories getEmbeddableFactories
@ -142,11 +140,10 @@ test('Returns title', async () => {
}); });
test('Returns an icon', async () => { test('Returns an icon', async () => {
let core: any;
let SavedObjectFinder: any; let SavedObjectFinder: any;
let notifications: any; let notifications: any;
const action = new ReplacePanelAction( const action = new ReplacePanelAction(
core, coreStart,
SavedObjectFinder, SavedObjectFinder,
notifications, notifications,
getEmbeddableFactories getEmbeddableFactories

View file

@ -21,7 +21,7 @@
import sizeMe from 'react-sizeme'; import sizeMe from 'react-sizeme';
import React from 'react'; 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 { skip } from 'rxjs/operators';
import { EmbeddableFactory, GetEmbeddableFactory } from '../../embeddable_plugin'; import { EmbeddableFactory, GetEmbeddableFactory } from '../../embeddable_plugin';
import { DashboardGrid, DashboardGridProps } from './dashboard_grid'; import { DashboardGrid, DashboardGridProps } from './dashboard_grid';
@ -65,10 +65,14 @@ function prepare(props?: Partial<DashboardGridProps>) {
} as any, } as any,
notifications: {} as any, notifications: {} as any,
overlays: {} as any, overlays: {} as any,
inspector: {} as any, inspector: {
isAvailable: jest.fn(),
} as any,
SavedObjectFinder: () => null, SavedObjectFinder: () => null,
ExitFullScreenButton: () => null, ExitFullScreenButton: () => null,
uiActions: {} as any, uiActions: {
getTriggerCompatibleActions: (() => []) as any,
} as any,
}; };
dashboardContainer = new DashboardContainer(initialInput, options); dashboardContainer = new DashboardContainer(initialInput, options);
const defaultTestProps: DashboardGridProps = { const defaultTestProps: DashboardGridProps = {
@ -100,12 +104,11 @@ test('renders DashboardGrid', () => {
<DashboardGrid {...props} /> <DashboardGrid {...props} />
</KibanaContextProvider> </KibanaContextProvider>
); );
const panelElements = component.find('EmbeddableChildPanel'); const panelElements = component.find('EmbeddableChildPanel');
expect(panelElements.length).toBe(2); expect(panelElements.length).toBe(2);
}); });
test('renders DashboardGrid with no visualizations', async () => { test('renders DashboardGrid with no visualizations', () => {
const { props, options } = prepare(); const { props, options } = prepare();
const component = mountWithIntl( const component = mountWithIntl(
<KibanaContextProvider services={options}> <KibanaContextProvider services={options}>
@ -114,12 +117,11 @@ test('renders DashboardGrid with no visualizations', async () => {
); );
props.container.updateInput({ panels: {} }); props.container.updateInput({ panels: {} });
await nextTick();
component.update(); component.update();
expect(component.find('EmbeddableChildPanel').length).toBe(0); 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 { props, options } = prepare();
const component = mountWithIntl( const component = mountWithIntl(
<KibanaContextProvider services={options}> <KibanaContextProvider services={options}>
@ -131,13 +133,12 @@ test('DashboardGrid removes panel when removed from container', async () => {
const filteredPanels = { ...originalPanels }; const filteredPanels = { ...originalPanels };
delete filteredPanels['1']; delete filteredPanels['1'];
props.container.updateInput({ panels: filteredPanels }); props.container.updateInput({ panels: filteredPanels });
await nextTick();
component.update(); component.update();
const panelElements = component.find('EmbeddableChildPanel'); const panelElements = component.find('EmbeddableChildPanel');
expect(panelElements.length).toBe(1); expect(panelElements.length).toBe(1);
}); });
test('DashboardGrid renders expanded panel', async () => { test('DashboardGrid renders expanded panel', () => {
const { props, options } = prepare(); const { props, options } = prepare();
const component = mountWithIntl( const component = mountWithIntl(
<KibanaContextProvider services={options}> <KibanaContextProvider services={options}>
@ -146,7 +147,6 @@ test('DashboardGrid renders expanded panel', async () => {
); );
props.container.updateInput({ expandedPanelId: '1' }); props.container.updateInput({ expandedPanelId: '1' });
await nextTick();
component.update(); component.update();
// Both panels should still exist in the dom, so nothing needs to be re-fetched once minimized. // Both panels should still exist in the dom, so nothing needs to be re-fetched once minimized.
expect(component.find('EmbeddableChildPanel').length).toBe(2); expect(component.find('EmbeddableChildPanel').length).toBe(2);
@ -156,7 +156,6 @@ test('DashboardGrid renders expanded panel', async () => {
).toBe('1'); ).toBe('1');
props.container.updateInput({ expandedPanelId: undefined }); props.container.updateInput({ expandedPanelId: undefined });
await nextTick();
component.update(); component.update();
expect(component.find('EmbeddableChildPanel').length).toBe(2); expect(component.find('EmbeddableChildPanel').length).toBe(2);

View file

@ -56,10 +56,14 @@ function getProps(
} as any, } as any,
notifications: {} as any, notifications: {} as any,
overlays: {} as any, overlays: {} as any,
inspector: {} as any, inspector: {
isAvailable: jest.fn(),
} as any,
SavedObjectFinder: () => null, SavedObjectFinder: () => null,
ExitFullScreenButton, ExitFullScreenButton,
uiActions: {} as any, uiActions: {
getTriggerCompatibleActions: (() => []) as any,
} as any,
}; };
const input = getSampleDashboardInput({ const input = getSampleDashboardInput({

View file

@ -148,6 +148,74 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA
"setIsCollapsed": [MockFunction], "setIsCollapsed": [MockFunction],
"setIsVisible": [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 { "docLinks": Object {
"DOC_LINK_VERSION": "mocked-test-branch", "DOC_LINK_VERSION": "mocked-test-branch",
"ELASTIC_WEBSITE_URL": "https://www.elastic.co/", "ELASTIC_WEBSITE_URL": "https://www.elastic.co/",
@ -710,6 +778,74 @@ exports[`QueryStringInput Should disable autoFocus on EuiFieldText when disableA
"setIsCollapsed": [MockFunction], "setIsCollapsed": [MockFunction],
"setIsVisible": [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 { "docLinks": Object {
"DOC_LINK_VERSION": "mocked-test-branch", "DOC_LINK_VERSION": "mocked-test-branch",
"ELASTIC_WEBSITE_URL": "https://www.elastic.co/", "ELASTIC_WEBSITE_URL": "https://www.elastic.co/",
@ -1260,6 +1396,74 @@ exports[`QueryStringInput Should pass the query language to the language switche
"setIsCollapsed": [MockFunction], "setIsCollapsed": [MockFunction],
"setIsVisible": [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 { "docLinks": Object {
"DOC_LINK_VERSION": "mocked-test-branch", "DOC_LINK_VERSION": "mocked-test-branch",
"ELASTIC_WEBSITE_URL": "https://www.elastic.co/", "ELASTIC_WEBSITE_URL": "https://www.elastic.co/",
@ -1819,6 +2023,74 @@ exports[`QueryStringInput Should pass the query language to the language switche
"setIsCollapsed": [MockFunction], "setIsCollapsed": [MockFunction],
"setIsVisible": [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 { "docLinks": Object {
"DOC_LINK_VERSION": "mocked-test-branch", "DOC_LINK_VERSION": "mocked-test-branch",
"ELASTIC_WEBSITE_URL": "https://www.elastic.co/", "ELASTIC_WEBSITE_URL": "https://www.elastic.co/",
@ -2369,6 +2641,74 @@ exports[`QueryStringInput Should render the given query 1`] = `
"setIsCollapsed": [MockFunction], "setIsCollapsed": [MockFunction],
"setIsVisible": [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 { "docLinks": Object {
"DOC_LINK_VERSION": "mocked-test-branch", "DOC_LINK_VERSION": "mocked-test-branch",
"ELASTIC_WEBSITE_URL": "https://www.elastic.co/", "ELASTIC_WEBSITE_URL": "https://www.elastic.co/",
@ -2928,6 +3268,74 @@ exports[`QueryStringInput Should render the given query 1`] = `
"setIsCollapsed": [MockFunction], "setIsCollapsed": [MockFunction],
"setIsVisible": [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 { "docLinks": Object {
"DOC_LINK_VERSION": "mocked-test-branch", "DOC_LINK_VERSION": "mocked-test-branch",
"ELASTIC_WEBSITE_URL": "https://www.elastic.co/", "ELASTIC_WEBSITE_URL": "https://www.elastic.co/",

View file

@ -24,6 +24,7 @@ import { mount } from 'enzyme';
import { QueryBarTopRow } from './query_bar_top_row'; import { QueryBarTopRow } from './query_bar_top_row';
import { coreMock } from '../../../../../core/public/mocks'; import { coreMock } from '../../../../../core/public/mocks';
import { dataPluginMock } from '../../mocks';
import { KibanaContextProvider } from 'src/plugins/kibana_react/public'; import { KibanaContextProvider } from 'src/plugins/kibana_react/public';
import { I18nProvider } from '@kbn/i18n/react'; import { I18nProvider } from '@kbn/i18n/react';
import { stubIndexPatternWithFields } from '../../stubs'; import { stubIndexPatternWithFields } from '../../stubs';
@ -95,6 +96,7 @@ function wrapQueryBarTopRowInContext(testProps: any) {
const services = { const services = {
...startMock, ...startMock,
data: dataPluginMock.createStartContract(),
appName: 'discover', appName: 'discover',
storage: createMockStorage(), storage: createMockStorage(),
}; };
@ -117,7 +119,7 @@ describe('QueryBarTopRowTopRow', () => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
it('Should render the given query', () => { it('Should render query and time picker', () => {
const component = mount( const component = mount(
wrapQueryBarTopRowInContext({ wrapQueryBarTopRowInContext({
query: kqlQuery, query: kqlQuery,

View file

@ -28,6 +28,7 @@ import React from 'react';
import { QueryLanguageSwitcher } from './language_switcher'; import { QueryLanguageSwitcher } from './language_switcher';
import { QueryStringInput, QueryStringInputUI } from './query_string_input'; import { QueryStringInput, QueryStringInputUI } from './query_string_input';
import { coreMock } from '../../../../../core/public/mocks'; import { coreMock } from '../../../../../core/public/mocks';
import { dataPluginMock } from '../../mocks';
const startMock = coreMock.createStart(); const startMock = coreMock.createStart();
import { stubIndexPatternWithFields } from '../../stubs'; import { stubIndexPatternWithFields } from '../../stubs';
@ -74,6 +75,7 @@ function wrapQueryStringInputInContext(testProps: any, storage?: any) {
const services = { const services = {
...startMock, ...startMock,
data: dataPluginMock.createStartContract(),
appName: testProps.appName || 'test', appName: testProps.appName || 'test',
storage: storage || createMockStorage(), storage: storage || createMockStorage(),
}; };

View file

@ -251,6 +251,7 @@ describe('SavedObjectsFinder', () => {
it('should include additional fields in search if listed in meta data', async () => { it('should include additional fields in search if listed in meta data', async () => {
const core = coreMock.createStart(); const core = coreMock.createStart();
core.uiSettings.get.mockImplementation(() => 10); core.uiSettings.get.mockImplementation(() => 10);
(core.savedObjects.client.find as jest.Mock).mockResolvedValue({ savedObjects: [] });
const wrapper = shallow( const wrapper = shallow(
<SavedObjectFinder <SavedObjectFinder
@ -631,6 +632,7 @@ describe('SavedObjectsFinder', () => {
describe('loading state', () => { describe('loading state', () => {
it('should display a spinner during initial loading', () => { it('should display a spinner during initial loading', () => {
const core = coreMock.createStart(); const core = coreMock.createStart();
(core.savedObjects.client.find as jest.Mock).mockResolvedValue({ savedObjects: [] });
const wrapper = shallow( const wrapper = shallow(
<SavedObjectFinder <SavedObjectFinder

View file

@ -17,14 +17,12 @@
* under the License. * under the License.
*/ */
import bluebird, { import bluebird, { promisify } from 'bluebird';
fromNode,
promisify,
} from 'bluebird';
import Handlebars from 'handlebars'; import Handlebars from 'handlebars';
import fs from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import imageDiff from 'image-diff'; import { PNG } from 'pngjs';
import pixelmatch from 'pixelmatch';
import moment from 'moment'; import moment from 'moment';
import SimpleGit from 'simple-git'; import SimpleGit from 'simple-git';
@ -110,17 +108,23 @@ async function compareScreenshots() {
screenshot screenshot
); );
// Diff the images asynchronously. const sessionImage = PNG.sync.read(await fs.promises.readFile(sessionImagePath));
const diffResult = await fromNode((cb) => { const baselineImage = PNG.sync.read(await fs.promises.readFile(baselineImagePath));
imageDiff.getFullResult({ const { width, height } = sessionImage;
actualImage: sessionImagePath, const diff = new PNG({ width, height });
expectedImage: baselineImagePath,
diffImage: diffImagePath,
shadow: true,
}, cb);
});
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); const changePercentage = (change * 100).toFixed(2);
console.log(`(${changePercentage}%) ${screenshot}`); console.log(`(${changePercentage}%) ${screenshot}`);
comparison.percentage = changePercentage; comparison.percentage = changePercentage;

View file

@ -27,7 +27,7 @@ describe('createErrorGroupWatch', () => {
.mockResolvedValue(undefined); .mockResolvedValue(undefined);
beforeEach(async () => { beforeEach(async () => {
jest.spyOn(uuid, 'v4').mockReturnValue(new Buffer('mocked-uuid')); jest.spyOn(uuid, 'v4').mockReturnValue(Buffer.from('mocked-uuid'));
createWatchResponse = await createErrorGroupWatch({ createWatchResponse = await createErrorGroupWatch({
http: {} as HttpServiceBase, http: {} as HttpServiceBase,

View file

@ -10,3 +10,5 @@ export const toastNotifications = {
addWarning: () => {}, addWarning: () => {},
addError: () => {}, addError: () => {},
}; };
export function fatalError() {}

View file

@ -266,7 +266,6 @@ export class ReportInfoButton extends Component<Props, State> {
info: null, info: null,
error: kfetchError, error: kfetchError,
}); });
throw kfetchError;
} }
} }
}; };

View file

@ -246,7 +246,9 @@ describe('Worker class', function () {
it('should use error multiplier when processPendingJobs rejects the Promise', async function () { it('should use error multiplier when processPendingJobs rejects the Promise', async function () {
worker = new Worker(mockQueue, 'test', noop, defaultWorkerOptions); 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); await allowPoll(defaultWorkerOptions.interval);
expect(processPendingJobsStub.callCount).to.be(1); expect(processPendingJobsStub.callCount).to.be(1);
@ -517,7 +519,7 @@ describe('Worker class', function () {
it('should emit for errors from claiming job', function (done) { it('should emit for errors from claiming job', function (done) {
sinon.stub(mockQueue.client, 'callWithInternalUser') sinon.stub(mockQueue.client, 'callWithInternalUser')
.withArgs('update') .withArgs('update')
.returns(Promise.reject({ statusCode: 401 })); .rejects({ statusCode: 401 });
worker.once(constants.EVENT_WORKER_JOB_CLAIM_ERROR, function (err) { worker.once(constants.EVENT_WORKER_JOB_CLAIM_ERROR, function (err) {
try { 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 () { it('should reject the promise if an error claiming the job', function () {
sinon.stub(mockQueue.client, 'callWithInternalUser') sinon.stub(mockQueue.client, 'callWithInternalUser')
.withArgs('update') .withArgs('update')
.returns(Promise.reject({ statusCode: 409 })); .rejects({ statusCode: 409 });
return worker._claimPendingJobs(getMockJobs()) return worker._claimPendingJobs(getMockJobs())
.catch(err => { .catch(err => {
expect(err).to.eql({ statusCode: 409 }); expect(err).to.eql({ statusCode: 409 });
@ -547,7 +549,7 @@ describe('Worker class', function () {
it('should get the pending job', function () { it('should get the pending job', function () {
sinon.stub(mockQueue.client, 'callWithInternalUser') sinon.stub(mockQueue.client, 'callWithInternalUser')
.withArgs('update') .withArgs('update')
.returns(Promise.resolve({ test: 'cool' })); .resolves({ test: 'cool' });
sinon.stub(worker, '_performJob').callsFake(identity); sinon.stub(worker, '_performJob').callsFake(identity);
return worker._claimPendingJobs(getMockJobs()) return worker._claimPendingJobs(getMockJobs())
.then(claimedJob => { .then(claimedJob => {
@ -607,7 +609,7 @@ describe('Worker class', function () {
mockQueue.client.callWithInternalUser.restore(); mockQueue.client.callWithInternalUser.restore();
sinon.stub(mockQueue.client, 'callWithInternalUser') sinon.stub(mockQueue.client, 'callWithInternalUser')
.withArgs('update') .withArgs('update')
.returns(Promise.reject({ statusCode: 409 })); .rejects({ statusCode: 409 });
return worker._failJob(job) return worker._failJob(job)
.then((res) => expect(res).to.equal(true)); .then((res) => expect(res).to.equal(true));
}); });
@ -616,7 +618,7 @@ describe('Worker class', function () {
mockQueue.client.callWithInternalUser.restore(); mockQueue.client.callWithInternalUser.restore();
sinon.stub(mockQueue.client, 'callWithInternalUser') sinon.stub(mockQueue.client, 'callWithInternalUser')
.withArgs('update') .withArgs('update')
.returns(Promise.reject({ statusCode: 401 })); .rejects({ statusCode: 401 });
return worker._failJob(job) return worker._failJob(job)
.then((res) => expect(res).to.equal(false)); .then((res) => expect(res).to.equal(false));
}); });
@ -654,7 +656,7 @@ describe('Worker class', function () {
mockQueue.client.callWithInternalUser.restore(); mockQueue.client.callWithInternalUser.restore();
sinon.stub(mockQueue.client, 'callWithInternalUser') sinon.stub(mockQueue.client, 'callWithInternalUser')
.withArgs('update') .withArgs('update')
.returns(Promise.reject({ statusCode: 401 })); .rejects({ statusCode: 401 });
worker.on(constants.EVENT_WORKER_FAIL_UPDATE_ERROR, function (err) { worker.on(constants.EVENT_WORKER_FAIL_UPDATE_ERROR, function (err) {
try { try {
@ -842,7 +844,7 @@ describe('Worker class', function () {
describe('job failures', function () { describe('job failures', function () {
function getFailStub(workerWithFailure) { function getFailStub(workerWithFailure) {
return sinon.stub(workerWithFailure, '_failJob').returns(Promise.resolve()); return sinon.stub(workerWithFailure, '_failJob').resolves();
} }
describe('saving output failure', () => { describe('saving output failure', () => {
@ -857,7 +859,7 @@ describe('Worker class', function () {
sinon.stub(mockQueue.client, 'callWithInternalUser') sinon.stub(mockQueue.client, 'callWithInternalUser')
.withArgs('update') .withArgs('update')
.returns(Promise.reject({ statusCode: 413 })); .rejects({ statusCode: 413 });
const workerFn = function (jobPayload) { const workerFn = function (jobPayload) {
return new Promise(function (resolve) { return new Promise(function (resolve) {
@ -878,7 +880,7 @@ describe('Worker class', function () {
it('causes _processPendingJobs to reject the Promise', function () { it('causes _processPendingJobs to reject the Promise', function () {
sinon.stub(mockQueue.client, 'callWithInternalUser') sinon.stub(mockQueue.client, 'callWithInternalUser')
.withArgs('search') .withArgs('search')
.returns(Promise.reject(new Error('test error'))); .rejects(new Error('test error'));
worker = new Worker(mockQueue, 'test', noop, defaultWorkerOptions); worker = new Worker(mockQueue, 'test', noop, defaultWorkerOptions);
return worker._processPendingJobs() return worker._processPendingJobs()
.then(() => { .then(() => {

View file

@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`it renders without crashing 1`] = `null`; exports[`it renders without crashing 1`] = `<Fragment />`;

View file

@ -10,31 +10,36 @@ import { RoleValidator } from '../../../lib/validate_role';
import { IndexPrivilegeForm } from './index_privilege_form'; import { IndexPrivilegeForm } from './index_privilege_form';
import { IndexPrivileges } from './index_privileges'; 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 = { const props = {
role: { role: {
name: '', name: '',
kibana: [],
elasticsearch: { elasticsearch: {
cluster: [], cluster: [],
indices: [], indices: [],
run_as: [], run_as: [],
}, },
kibana: [],
}, },
httpClient: jest.fn(), httpClient: jest.fn(),
onChange: jest.fn(), onChange: jest.fn(),
indexPatterns: [], indexPatterns: [],
editable: true,
allowDocumentLevelSecurity: true, allowDocumentLevelSecurity: true,
allowFieldLevelSecurity: true, allowFieldLevelSecurity: true,
editable: true,
validator: new RoleValidator(), validator: new RoleValidator(),
availableIndexPrivileges: ['all', 'read', 'write', 'index'], availableIndexPrivileges: ['all', 'read', 'write', 'index'],
}; };
const wrapper = shallowWithIntl(<IndexPrivileges {...props} />); const wrapper = shallowWithIntl(<IndexPrivileges {...props} />);
await flushPromises();
expect(wrapper).toMatchSnapshot(); 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 = { const props = {
role: { role: {
name: '', name: '',
@ -64,5 +69,6 @@ test('it renders a IndexPrivilegeForm for each privilege on the role', () => {
availableIndexPrivileges: ['all', 'read', 'write', 'index'], availableIndexPrivileges: ['all', 'read', 'write', 'index'],
}; };
const wrapper = mountWithIntl(<IndexPrivileges {...props} />); const wrapper = mountWithIntl(<IndexPrivileges {...props} />);
await flushPromises();
expect(wrapper.find(IndexPrivilegeForm)).toHaveLength(1); expect(wrapper.find(IndexPrivilegeForm)).toHaveLength(1);
}); });

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License. * you may not use this file except in compliance with the Elastic License.
*/ */
import _ from 'lodash'; import _ from 'lodash';
import React, { Component } from 'react'; import React, { Component, Fragment } from 'react';
import { Role, RoleIndexPrivilege } from '../../../../../../../common/model'; import { Role, RoleIndexPrivilege } from '../../../../../../../common/model';
import { isReadOnlyRole, isRoleEnabled } from '../../../../../../lib/role_utils'; import { isReadOnlyRole, isRoleEnabled } from '../../../../../../lib/role_utils';
import { getFields } from '../../../../../../objects'; import { getFields } from '../../../../../../objects';
@ -74,7 +74,7 @@ export class IndexPrivileges extends Component<Props, State> {
/> />
)); ));
return forms; return <Fragment>{forms}</Fragment>;
} }
public addIndexPrivilege = () => { public addIndexPrivilege = () => {

View file

@ -23,7 +23,12 @@ function mockGetXPackLicense(callCluster, license, req) {
local: 'true' 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', { callCluster.withArgs('transport.request', {
method: 'GET', 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 // 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) { function mockGetXPackUsage(callCluster, usage, req) {

View file

@ -151,7 +151,7 @@
"null-loader": "^3.0.0", "null-loader": "^3.0.0",
"pdf-image": "2.0.0", "pdf-image": "2.0.0",
"pdfjs-dist": "^2.0.943", "pdfjs-dist": "^2.0.943",
"pixelmatch": "4.0.2", "pixelmatch": "^5.1.0",
"proxyquire": "1.8.0", "proxyquire": "1.8.0",
"react-docgen-typescript-loader": "^3.1.1", "react-docgen-typescript-loader": "^3.1.1",
"react-test-renderer": "^16.12.0", "react-test-renderer": "^16.12.0",

View file

@ -516,16 +516,19 @@ describe('Authenticator', () => {
expect(mockSessionStorage.clear).not.toHaveBeenCalled(); expect(mockSessionStorage.clear).not.toHaveBeenCalled();
}); });
it('only updates the session lifespan expiration if it does not match the current server config.', async () => { describe('conditionally updates the session lifespan expiration', () => {
const user = mockAuthenticatedUser();
const request = httpServerMock.createKibanaRequest();
const hr = 1000 * 60 * 60; const hr = 1000 * 60 * 60;
const currentDate = new Date(Date.UTC(2019, 10, 10)).valueOf();
async function createAndUpdateSession( async function createAndUpdateSession(
lifespan: number | null, lifespan: number | null,
oldExpiration: number | null, oldExpiration: number | null,
newExpiration: number | null newExpiration: number | null
) { ) {
const user = mockAuthenticatedUser();
const request = httpServerMock.createKibanaRequest();
jest.spyOn(Date, 'now').mockImplementation(() => currentDate);
mockOptions = getMockOptions({ mockOptions = getMockOptions({
session: { session: {
idleTimeout: null, idleTimeout: null,
@ -537,7 +540,7 @@ describe('Authenticator', () => {
mockSessionStorage = sessionStorageMock.create(); mockSessionStorage = sessionStorageMock.create();
mockSessionStorage.get.mockResolvedValue({ mockSessionStorage.get.mockResolvedValue({
...mockSessVal, ...mockSessVal,
idleTimeoutExpiration: 1, idleTimeoutExpiration: null,
lifespanExpiration: oldExpiration, lifespanExpiration: oldExpiration,
}); });
mockOptions.sessionStorageFactory.asScoped.mockReturnValue(mockSessionStorage); mockOptions.sessionStorageFactory.asScoped.mockReturnValue(mockSessionStorage);
@ -555,17 +558,24 @@ describe('Authenticator', () => {
expect(mockSessionStorage.set).toHaveBeenCalledTimes(1); expect(mockSessionStorage.set).toHaveBeenCalledTimes(1);
expect(mockSessionStorage.set).toHaveBeenCalledWith({ expect(mockSessionStorage.set).toHaveBeenCalledWith({
...mockSessVal, ...mockSessVal,
idleTimeoutExpiration: 1, idleTimeoutExpiration: null,
lifespanExpiration: newExpiration, lifespanExpiration: newExpiration,
}); });
expect(mockSessionStorage.clear).not.toHaveBeenCalled(); expect(mockSessionStorage.clear).not.toHaveBeenCalled();
} }
// do not change max expiration
createAndUpdateSession(hr * 8, 1234, 1234); it('does not change a non-null lifespan expiration when configured to non-null value.', async () => {
createAndUpdateSession(null, null, null); await createAndUpdateSession(hr * 8, 1234, 1234);
// change max expiration });
createAndUpdateSession(null, 1234, null); it('does not change a null lifespan expiration when configured to null value.', async () => {
createAndUpdateSession(hr * 8, null, hr * 8); 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 () => { it('does not touch session for system API calls if authentication fails with non-401 reason.', async () => {

View file

@ -5495,21 +5495,11 @@ array-map@~0.0.0:
resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662"
integrity sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI= 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: array-reduce@~0.0.0:
version "0.0.0" version "0.0.0"
resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b"
integrity sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys= 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: array-slice@^0.2.3:
version "0.2.3" version "0.2.3"
resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5"
@ -5785,11 +5775,6 @@ async@^2.6.3:
dependencies: dependencies:
lodash "^4.17.14" 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: async@~1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9" 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" base64-js "^1.0.2"
ieee754 "^1.1.4" 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: builtin-modules@^1.0.0:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
@ -8345,13 +8321,6 @@ commander@~2.8.1:
dependencies: dependencies:
graceful-readlink ">= 1.0.0" 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: common-tags@1.8.0, common-tags@^1.8.0:
version "1.8.0" version "1.8.0"
resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.0.tgz#8e3153e542d4a39e9b10554434afaaf98956a937" 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" node-fetch "2.1.2"
whatwg-fetch "2.0.4" 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: cross-spawn-async@^2.1.1:
version "2.2.5" version "2.2.5"
resolved "https://registry.yarnpkg.com/cross-spawn-async/-/cross-spawn-async-2.2.5.tgz#845ff0c0834a3ded9d160daca6d390906bb288cc" 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" memoizee "0.4.X"
object-assign "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" version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
@ -10968,11 +10929,6 @@ enzyme@^3.10.0:
rst-selector-parser "^2.2.3" rst-selector-parser "^2.2.3"
string.prototype.trim "^1.1.2" 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: errlop@^1.1.2:
version "1.1.2" version "1.1.2"
resolved "https://registry.yarnpkg.com/errlop/-/errlop-1.1.2.tgz#a99a48f37aa264d614e342ffdbbaa49eec9220e0" resolved "https://registry.yarnpkg.com/errlop/-/errlop-1.1.2.tgz#a99a48f37aa264d614e342ffdbbaa49eec9220e0"
@ -13809,15 +13765,6 @@ glogg@^1.0.0:
dependencies: dependencies:
sparkles "^1.0.0" 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: gonzales-pe-sl@^4.2.3:
version "4.2.3" version "4.2.3"
resolved "https://registry.yarnpkg.com/gonzales-pe-sl/-/gonzales-pe-sl-4.2.3.tgz#6a868bc380645f141feeb042c6f97fcc71b59fe6" 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" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.2.tgz#e28e584d43ad7e92f96995019cc43b9e1ac49558"
integrity sha512-vdqWBp7MyzdmHkkRWV5nY+PfGRbYbahfuvsBCh277tq+w9zyNi7h5CYJCK0kmzti9kU+O/cB7sE8HvKv6aXAKQ== 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: image-size@~0.5.0:
version "0.5.5" version "0.5.5"
resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" 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" pseudomap "^1.0.2"
yallist "^2.1.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: lru-cache@^5.1.1:
version "5.1.1" version "5.1.1"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" 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" for-in "^0.1.3"
is-extendable "^0.1.1" 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" version "0.3.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7"
integrity sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc= integrity sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=
@ -21797,13 +21727,20 @@ pirates@^4.0.0, pirates@^4.0.1:
dependencies: dependencies:
node-modules-regexp "^1.0.0" node-modules-regexp "^1.0.0"
pixelmatch@4.0.2, pixelmatch@^4.0.2: pixelmatch@^4.0.2:
version "4.0.2" version "4.0.2"
resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-4.0.2.tgz#8f47dcec5011b477b67db03c243bc1f3085e8854" resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-4.0.2.tgz#8f47dcec5011b477b67db03c243bc1f3085e8854"
integrity sha1-j0fc7FARtHe2fbA8JDvB8wheiFQ= integrity sha1-j0fc7FARtHe2fbA8JDvB8wheiFQ=
dependencies: dependencies:
pngjs "^3.0.0" 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: pkg-dir@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" 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" rimraf "^2.6.1"
ws "^6.1.0" ws "^6.1.0"
q@^1.0.1, q@^1.1.2: q@^1.1.2:
version "1.5.1" version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
@ -27422,11 +27359,6 @@ titleize@^1.0.1:
resolved "https://registry.yarnpkg.com/titleize/-/titleize-1.0.1.tgz#21bc24fcca658eadc6d3bd3c38f2bd173769b4c5" resolved "https://registry.yarnpkg.com/titleize/-/titleize-1.0.1.tgz#21bc24fcca658eadc6d3bd3c38f2bd173769b4c5"
integrity sha512-rUwGDruKq1gX+FFHbTl5qjI7teVO7eOe+C8IcQ7QT+1BK3eEUXJqbZcBOeaRP4FwSC/C1A5jDoIVta0nIQ9yew== 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: tmp@0.0.30:
version "0.0.30" version "0.0.30"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed"