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",
"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",

View file

@ -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

View file

@ -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');
}
}

View file

@ -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,

View file

@ -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

View file

@ -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 () {

View file

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

View file

@ -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

View file

@ -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);
});
});

View file

@ -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 });

View file

@ -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;
});
};

View file

@ -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'),
},
},
};

View file

@ -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);
}
}

View file

@ -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() {

View file

@ -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<string, EmbeddableFactory>();
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

View file

@ -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<DashboardGridProps>) {
} 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', () => {
<DashboardGrid {...props} />
</KibanaContextProvider>
);
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(
<KibanaContextProvider services={options}>
@ -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(
<KibanaContextProvider services={options}>
@ -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(
<KibanaContextProvider services={options}>
@ -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);

View file

@ -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({

View file

@ -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/",

View file

@ -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,

View file

@ -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(),
};

View file

@ -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(
<SavedObjectFinder
@ -631,6 +632,7 @@ describe('SavedObjectsFinder', () => {
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(
<SavedObjectFinder

View file

@ -17,14 +17,12 @@
* under the License.
*/
import bluebird, {
fromNode,
promisify,
} from 'bluebird';
import bluebird, { promisify } from 'bluebird';
import Handlebars from 'handlebars';
import fs from 'fs';
import path from 'path';
import imageDiff from 'image-diff';
import { PNG } from 'pngjs';
import pixelmatch from 'pixelmatch';
import moment from 'moment';
import SimpleGit from 'simple-git';
@ -110,17 +108,23 @@ async function compareScreenshots() {
screenshot
);
// Diff the images asynchronously.
const diffResult = await fromNode((cb) => {
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;

View file

@ -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,

View file

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

View file

@ -266,7 +266,6 @@ export class ReportInfoButton extends Component<Props, State> {
info: null,
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 () {
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(() => {

View file

@ -1,3 +1,3 @@
// 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 { 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(<IndexPrivileges {...props} />);
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(<IndexPrivileges {...props} />);
await flushPromises();
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.
*/
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<Props, State> {
/>
));
return forms;
return <Fragment>{forms}</Fragment>;
}
public addIndexPrivilege = () => {

View file

@ -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) {

View file

@ -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",

View file

@ -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 () => {

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"
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"