From e5c3b4ef18b94b45632519fc58fcbd11d6da12c7 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Mon, 20 Apr 2020 14:32:28 -0700 Subject: [PATCH 1/2] Warn when using qgrid > 1.1.1 --- package.nls.json | 3 +- src/client/common/utils/localize.ts | 4 ++ src/client/datascience/constants.ts | 1 + .../interactiveWindowTypes.ts | 7 ++- .../interactive-common/synchronization.ts | 2 + .../ipywidgets/ipywidgetHandler.ts | 15 +++++- src/client/telemetry/index.ts | 4 ++ .../history-react/redux/reducers/index.ts | 1 + .../redux/reducers/commonEffects.ts | 39 ++++++++++++++- .../redux/reducers/types.ts | 6 +++ src/datascience-ui/ipywidgets/container.tsx | 45 +++++++++++++++-- .../ipywidgets/incompatibleWidgetHandler.ts | 47 ++++++++++++++++++ .../native-editor/redux/reducers/index.ts | 1 + .../incompatibleWidgetHandler.unit.test.ts | 49 +++++++++++++++++++ 14 files changed, 214 insertions(+), 10 deletions(-) create mode 100644 src/datascience-ui/ipywidgets/incompatibleWidgetHandler.ts create mode 100644 src/test/datascience/ipywidgets/incompatibleWidgetHandler.unit.test.ts diff --git a/package.nls.json b/package.nls.json index 645ed3b109b9..4f4fd78183f7 100644 --- a/package.nls.json +++ b/package.nls.json @@ -474,5 +474,6 @@ "DataScience.loadThirdPartyWidgetScriptsPostEnabled": "Please restart the Kernel when changing the setting 'python.dataScience.widgetScriptSources'.", "DataScience.enableCDNForWidgetsSetting": "Widgets require us to download supporting files from a 3rd party website. Click here to enable this or click here for more information. (Error loading {0}:{1}).", "DataScience.widgetScriptNotFoundOnCDNWidgetMightNotWork": "Unable to load a compatible version of the widget '{0}'. Expected behavior may be affected.", - "DataScience.unhandledMessage": "Unhandled kernel message from a widget: {0} : {1}" + "DataScience.unhandledMessage": "Unhandled kernel message from a widget: {0} : {1}", + "DataScience.qgridWidgetScriptVersionCompatibilityWarning": "Unable to load a compatible version of the widget 'qgrid'. Consider downgrading to version 1.1.1." } diff --git a/src/client/common/utils/localize.ts b/src/client/common/utils/localize.ts index b799f8b2be9e..a34258332bf7 100644 --- a/src/client/common/utils/localize.ts +++ b/src/client/common/utils/localize.ts @@ -876,6 +876,10 @@ export namespace DataScience { 'DataScience.widgetScriptNotFoundOnCDNWidgetMightNotWork', "Unable to load a compatible version of the widget '{0}'. Expected behavior may be affected." ); + export const qgridWidgetScriptVersionCompatibilityWarning = localize( + 'DataScience.qgridWidgetScriptVersionCompatibilityWarning', + "Unable to load a compatible version of the widget 'qgrid'. Consider downgrading to version 1.1.1." + ); } export namespace DebugConfigStrings { diff --git a/src/client/datascience/constants.ts b/src/client/datascience/constants.ts index 27d39964adc1..2e35b17cad59 100644 --- a/src/client/datascience/constants.ts +++ b/src/client/datascience/constants.ts @@ -290,6 +290,7 @@ export enum Telemetry { ZMQNotSupported = 'DATASCIENCE.ZMQ_NATIVE_BINARIES_NOT_LOADING', IPyWidgetLoadSuccess = 'DS_INTERNAL.IPYWIDGET_LOAD_SUCCESS', IPyWidgetLoadFailure = 'DS_INTERNAL.IPYWIDGET_LOAD_FAILURE', + IPyWidgetWidgetVersionNotSupportedLoadFailure = 'DS_INTERNAL.IPYWIDGET_WIDGET_VERSION_NOT_SUPPORTED_LOAD_FAILURE', IPyWidgetLoadDisabled = 'DS_INTERNAL.IPYWIDGET_LOAD_DISABLED', HashedIPyWidgetNameUsed = 'DS_INTERNAL.IPYWIDGET_USED_BY_USER', HashedIPyWidgetNameDiscovered = 'DS_INTERNAL.IPYWIDGET_DISCOVERED', diff --git a/src/client/datascience/interactive-common/interactiveWindowTypes.ts b/src/client/datascience/interactive-common/interactiveWindowTypes.ts index 4084e23650b1..336de7366104 100644 --- a/src/client/datascience/interactive-common/interactiveWindowTypes.ts +++ b/src/client/datascience/interactive-common/interactiveWindowTypes.ts @@ -10,7 +10,8 @@ import { CommonActionType, IAddCellAction, ILoadIPyWidgetClassFailureAction, - LoadIPyWidgetClassLoadAction + LoadIPyWidgetClassLoadAction, + NotifyIPyWidgeWidgetVersionNotSupportedAction } from '../../../datascience-ui/interactive-common/redux/reducers/types'; import { PythonInterpreter } from '../../interpreter/contracts'; import { NativeKeyboardCommandTelemetry, NativeMouseCommandTelemetry } from '../constants'; @@ -117,7 +118,8 @@ export enum InteractiveWindowMessages { IPyWidgetLoadSuccess = 'ipywidget_load_success', IPyWidgetLoadFailure = 'ipywidget_load_failure', IPyWidgetRenderFailure = 'ipywidget_render_failure', - IPyWidgetUnhandledKernelMessage = 'ipywidget_unhandled_kernel_message' + IPyWidgetUnhandledKernelMessage = 'ipywidget_unhandled_kernel_message', + IPyWidgetWidgetVersionNotSupported = 'ipywidget_widget_version_not_supported' } export enum IPyWidgetMessages { @@ -580,6 +582,7 @@ export class IInteractiveWindowMapping { public [InteractiveWindowMessages.UpdateDisplayData]: KernelMessage.IUpdateDisplayDataMsg; public [InteractiveWindowMessages.IPyWidgetLoadSuccess]: LoadIPyWidgetClassLoadAction; public [InteractiveWindowMessages.IPyWidgetLoadFailure]: ILoadIPyWidgetClassFailureAction; + public [InteractiveWindowMessages.IPyWidgetWidgetVersionNotSupported]: NotifyIPyWidgeWidgetVersionNotSupportedAction; public [InteractiveWindowMessages.ConvertUriForUseInWebViewRequest]: Uri; public [InteractiveWindowMessages.ConvertUriForUseInWebViewResponse]: { request: Uri; response: Uri }; public [InteractiveWindowMessages.IPyWidgetRenderFailure]: Error; diff --git a/src/client/datascience/interactive-common/synchronization.ts b/src/client/datascience/interactive-common/synchronization.ts index b89308409ced..eeeb1f311082 100644 --- a/src/client/datascience/interactive-common/synchronization.ts +++ b/src/client/datascience/interactive-common/synchronization.ts @@ -88,6 +88,7 @@ const messageWithMessageTypes: MessageMapping & Messa [CommonActionType.FOCUS_INPUT]: MessageType.other, [CommonActionType.LOAD_IPYWIDGET_CLASS_SUCCESS]: MessageType.other, [CommonActionType.LOAD_IPYWIDGET_CLASS_FAILURE]: MessageType.other, + [CommonActionType.IPYWIDGET_WIDGET_VERSION_NOT_SUPPORTED]: MessageType.other, [CommonActionType.IPYWIDGET_RENDER_FAILURE]: MessageType.other, // Types from InteractiveWindowMessages @@ -119,6 +120,7 @@ const messageWithMessageTypes: MessageMapping & Messa [InteractiveWindowMessages.IPyWidgetLoadFailure]: MessageType.other, [InteractiveWindowMessages.IPyWidgetRenderFailure]: MessageType.other, [InteractiveWindowMessages.IPyWidgetUnhandledKernelMessage]: MessageType.other, + [InteractiveWindowMessages.IPyWidgetWidgetVersionNotSupported]: MessageType.other, [InteractiveWindowMessages.LoadAllCells]: MessageType.other, [InteractiveWindowMessages.LoadAllCellsComplete]: MessageType.other, [InteractiveWindowMessages.LoadOnigasmAssemblyRequest]: MessageType.other, diff --git a/src/client/datascience/ipywidgets/ipywidgetHandler.ts b/src/client/datascience/ipywidgets/ipywidgetHandler.ts index e26d2539e6ed..100dda03092b 100644 --- a/src/client/datascience/ipywidgets/ipywidgetHandler.ts +++ b/src/client/datascience/ipywidgets/ipywidgetHandler.ts @@ -9,7 +9,8 @@ import stripAnsi from 'strip-ansi'; import { Event, EventEmitter, Uri } from 'vscode'; import { ILoadIPyWidgetClassFailureAction, - LoadIPyWidgetClassLoadAction + LoadIPyWidgetClassLoadAction, + NotifyIPyWidgeWidgetVersionNotSupportedAction } from '../../../datascience-ui/interactive-common/redux/reducers/types'; import { EnableIPyWidgets } from '../../common/experimentGroups'; import { traceError, traceInfo } from '../../common/logger'; @@ -75,6 +76,8 @@ export class IPyWidgetHandler implements IInteractiveWindowListener { this.sendLoadSucceededTelemetry(payload); } else if (message === InteractiveWindowMessages.IPyWidgetLoadFailure) { this.sendLoadFailureTelemetry(payload); + } else if (message === InteractiveWindowMessages.IPyWidgetWidgetVersionNotSupported) { + this.sendUnsupportedWidgetVersionFailureTelemetry(payload); } else if (message === InteractiveWindowMessages.IPyWidgetRenderFailure) { this.sendRenderFailureTelemetry(payload); } else if (message === InteractiveWindowMessages.IPyWidgetUnhandledKernelMessage) { @@ -111,6 +114,16 @@ export class IPyWidgetHandler implements IInteractiveWindowListener { // do nothing on failure } } + private sendUnsupportedWidgetVersionFailureTelemetry(payload: NotifyIPyWidgeWidgetVersionNotSupportedAction) { + try { + sendTelemetryEvent(Telemetry.IPyWidgetWidgetVersionNotSupportedLoadFailure, 0, { + moduleHash: this.hash(payload.moduleName), + moduleVersion: payload.moduleVersion + }); + } catch { + // do nothing on failure + } + } private sendRenderFailureTelemetry(payload: Error) { try { traceError('Error rendering a widget: ', payload); diff --git a/src/client/telemetry/index.ts b/src/client/telemetry/index.ts index 9863bf234966..6e04f3bbcc31 100644 --- a/src/client/telemetry/index.ts +++ b/src/client/telemetry/index.ts @@ -1974,6 +1974,10 @@ export interface IEventNamePropertyMapping { // Whether we timedout getting the source of the script (fetching script source in extension code). timedout: boolean; }; + /** + * Telemetry event sent when an ipywidget version that is not supported is used & we have trapped this and warned the user abou it. + */ + [Telemetry.IPyWidgetWidgetVersionNotSupportedLoadFailure]: { moduleHash: string; moduleVersion: string }; /** * Telemetry event sent when an loading of 3rd party ipywidget JS scripts from 3rd party source has been disabled. */ diff --git a/src/datascience-ui/history-react/redux/reducers/index.ts b/src/datascience-ui/history-react/redux/reducers/index.ts index cece25877103..ba9db36b3a43 100644 --- a/src/datascience-ui/history-react/redux/reducers/index.ts +++ b/src/datascience-ui/history-react/redux/reducers/index.ts @@ -43,6 +43,7 @@ export const reducerMap: Partial = { [CommonActionType.FOCUS_INPUT]: CommonEffects.focusInput, [CommonActionType.LOAD_IPYWIDGET_CLASS_SUCCESS]: CommonEffects.handleLoadIPyWidgetClassSuccess, [CommonActionType.LOAD_IPYWIDGET_CLASS_FAILURE]: CommonEffects.handleLoadIPyWidgetClassFailure, + [CommonActionType.IPYWIDGET_WIDGET_VERSION_NOT_SUPPORTED]: CommonEffects.notifyAboutUnsupportedWidgetVersions, [CommonActionType.IPYWIDGET_RENDER_FAILURE]: CommonEffects.handleIPyWidgetRenderFailure, // Messages from the webview (some are ignored) diff --git a/src/datascience-ui/interactive-common/redux/reducers/commonEffects.ts b/src/datascience-ui/interactive-common/redux/reducers/commonEffects.ts index 814a01c2c550..7de7fbae8e6f 100644 --- a/src/datascience-ui/interactive-common/redux/reducers/commonEffects.ts +++ b/src/datascience-ui/interactive-common/redux/reducers/commonEffects.ts @@ -18,7 +18,8 @@ import { CommonReducerArg, ILoadIPyWidgetClassFailureAction, IOpenSettingsAction, - LoadIPyWidgetClassLoadAction + LoadIPyWidgetClassLoadAction, + NotifyIPyWidgeWidgetVersionNotSupportedAction } from './types'; export namespace CommonEffects { @@ -258,6 +259,42 @@ export namespace CommonEffects { return arg.prevState; } } + export function notifyAboutUnsupportedWidgetVersions( + arg: CommonReducerArg + ): IMainState { + // Find the first currently executing cell and add an error to its output + let index = arg.prevState.cellVMs.findIndex((c) => c.cell.state === CellState.executing); + + // If there isn't one, then find the latest that matches the current execution count. + if (index < 0) { + index = arg.prevState.cellVMs.findIndex( + (c) => c.cell.data.execution_count === arg.prevState.currentExecutionCount + ); + } + if (index >= 0 && arg.prevState.cellVMs[index].cell.data.cell_type === 'code') { + const newVMs = [...arg.prevState.cellVMs]; + const current = arg.prevState.cellVMs[index]; + + const errorMessage = getLocString( + 'DataScience.qgridWidgetScriptVersionCompatibilityWarning', + "Unable to load a compatible version of the widget 'qgrid'. Consider downgrading to version 1.1.1." + ); + newVMs[index] = Helpers.asCellViewModel({ + ...current, + uiSideError: errorMessage + }); + + // Make sure to tell the extension so it can log telemetry. + postActionToExtension(arg, InteractiveWindowMessages.IPyWidgetWidgetVersionNotSupported, arg.payload.data); + + return { + ...arg.prevState, + cellVMs: newVMs + }; + } else { + return arg.prevState; + } + } export function handleIPyWidgetRenderFailure(arg: CommonReducerArg): IMainState { // Make sure to tell the extension so it can log telemetry. postActionToExtension(arg, InteractiveWindowMessages.IPyWidgetRenderFailure, arg.payload.data); diff --git a/src/datascience-ui/interactive-common/redux/reducers/types.ts b/src/datascience-ui/interactive-common/redux/reducers/types.ts index 84c11e2edd98..28c8426925fb 100644 --- a/src/datascience-ui/interactive-common/redux/reducers/types.ts +++ b/src/datascience-ui/interactive-common/redux/reducers/types.ts @@ -59,6 +59,7 @@ export enum CommonActionType { IPYWIDGET_RENDER_FAILURE = 'action.ipywidget_render_failure', LOAD_IPYWIDGET_CLASS_SUCCESS = 'action.load_ipywidget_class_success', LOAD_IPYWIDGET_CLASS_FAILURE = 'action.load_ipywidget_class_failure', + IPYWIDGET_WIDGET_VERSION_NOT_SUPPORTED = 'action.ipywidget_widget_version_not_supported', LOADED_ALL_CELLS = 'action.loaded_all_cells', LINK_CLICK = 'action.link_click', MOVE_CELL_DOWN = 'action.move_cell_down', @@ -136,6 +137,7 @@ export type CommonActionTypeMapping = { [CommonActionType.FOCUS_INPUT]: never | undefined; [CommonActionType.LOAD_IPYWIDGET_CLASS_SUCCESS]: LoadIPyWidgetClassLoadAction; [CommonActionType.LOAD_IPYWIDGET_CLASS_FAILURE]: ILoadIPyWidgetClassFailureAction; + [CommonActionType.IPYWIDGET_WIDGET_VERSION_NOT_SUPPORTED]: NotifyIPyWidgeWidgetVersionNotSupportedAction; [CommonActionType.IPYWIDGET_RENDER_FAILURE]: Error; }; @@ -233,5 +235,9 @@ export type LoadIPyWidgetClassLoadAction = { moduleName: string; moduleVersion: string; }; +export type NotifyIPyWidgeWidgetVersionNotSupportedAction = { + moduleName: 'qgrid'; + moduleVersion: string; +}; export type CommonAction = ActionWithPayload; diff --git a/src/datascience-ui/ipywidgets/container.tsx b/src/datascience-ui/ipywidgets/container.tsx index 85e85c732b58..407f01c96c21 100644 --- a/src/datascience-ui/ipywidgets/container.tsx +++ b/src/datascience-ui/ipywidgets/container.tsx @@ -19,10 +19,12 @@ import { CommonAction, CommonActionType, ILoadIPyWidgetClassFailureAction, - LoadIPyWidgetClassLoadAction + LoadIPyWidgetClassLoadAction, + NotifyIPyWidgeWidgetVersionNotSupportedAction } from '../interactive-common/redux/reducers/types'; import { IStore } from '../interactive-common/redux/store'; import { PostOffice } from '../react-common/postOffice'; +import { warnAboutWidgetVersionsThatAreNotSupported } from './incompatibleWidgetHandler'; import { WidgetManager } from './manager'; import { registerScripts } from './requirejsRegistry'; @@ -35,6 +37,7 @@ type Props = { export class WidgetManagerComponent extends React.Component { private readonly widgetManager: WidgetManager; private readonly widgetSourceRequests = new Map>(); + private readonly registeredWidgetSources = new Map(); private timedoutWaitingForWidgetsToGetLoaded?: boolean; private widgetsCanLoadFromCDN: boolean = false; private readonly loaderSettings = { @@ -75,6 +78,7 @@ export class WidgetManagerComponent extends React.Component { // This happens when we have restarted a kernel. // If user changed the kernel, then some widgets might exist now and some might now. this.widgetSourceRequests.clear(); + this.registeredWidgetSources.clear(); } return true; } @@ -105,6 +109,7 @@ export class WidgetManagerComponent extends React.Component { // Now resolve promises (anything that was waiting for modules to get registered can carry on). sources.forEach((source) => { + this.registeredWidgetSources.set(source.moduleName, source); // We have fetched the script sources for all of these modules. // In some cases we might not have the source, meaning we don't have it or couldn't find it. let deferred = this.widgetSourceRequests.get(source.moduleName); @@ -157,6 +162,21 @@ export class WidgetManagerComponent extends React.Component { } }; } + private createWidgetVersionNotSupportedErrorAction( + moduleName: 'qgrid', + moduleVersion: string + ): CommonAction { + return { + type: CommonActionType.IPYWIDGET_WIDGET_VERSION_NOT_SUPPORTED, + payload: { + messageDirection: 'incoming', + data: { + moduleName, + moduleVersion + } + } + }; + } private async handleLoadError( className: string, moduleName: string, @@ -213,10 +233,25 @@ export class WidgetManagerComponent extends React.Component { { moduleName, moduleVersion } ); - return deferred.promise.catch((ex) => - // tslint:disable-next-line: no-console - console.error(`Failed to load Widget Script from Extension for for ${moduleName}, ${moduleVersion}`, ex) - ); + return deferred.promise + .then(() => { + const widgetSource = this.registeredWidgetSources.get(moduleName); + if (widgetSource) { + warnAboutWidgetVersionsThatAreNotSupported( + widgetSource, + moduleVersion, + this.widgetsCanLoadFromCDN, + (info) => + this.props.store.dispatch( + this.createWidgetVersionNotSupportedErrorAction(info.moduleName, info.moduleVersion) + ) + ); + } + }) + .catch((ex) => + // tslint:disable-next-line: no-console + console.error(`Failed to load Widget Script from Extension for for ${moduleName}, ${moduleVersion}`, ex) + ); } private handleLoadSuccess(className: string, moduleName: string, moduleVersion: string) { diff --git a/src/datascience-ui/ipywidgets/incompatibleWidgetHandler.ts b/src/datascience-ui/ipywidgets/incompatibleWidgetHandler.ts new file mode 100644 index 000000000000..a6d3ce4e1207 --- /dev/null +++ b/src/datascience-ui/ipywidgets/incompatibleWidgetHandler.ts @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +'use strict'; + +import * as semver from 'semver'; +import { WidgetScriptSource } from '../../client/datascience/ipywidgets/types'; +const supportedVersionOfQgrid = '1.1.1'; +const qgridModuleName = 'qgrid'; + +/** + * For now only warns about qgrid. + * Warn user about qgrid versions > 1.1.1 (we know CDN isn't available for newer versions and local widget source will not work). + * Recommend to downgrade to 1.1.1. + * Returns `true` if a warning has been displayed. + */ +export function warnAboutWidgetVersionsThatAreNotSupported( + widgetSource: WidgetScriptSource, + moduleVersion: string, + cdnSupported: boolean, + errorDispatcher: (info: { moduleName: typeof qgridModuleName; moduleVersion: string }) => void +) { + // if widget exists on CDN or CDN is disabled, get out. + if (widgetSource.source === 'cdn' || !cdnSupported) { + return false; + } + // Warn about qrid. + if (widgetSource.moduleName !== qgridModuleName) { + return false; + } + // We're only interested in versions > 1.1.1. + try { + // If we have an exact version, & if that is <= 1.1.1, then no warning needs to be displayed. + if (!moduleVersion.startsWith('^') && semver.compare(moduleVersion, supportedVersionOfQgrid) <= 0) { + return false; + } + // If we have a version range, then check the range. + // Basically if our minimum version 1.1.1 is met, then nothing to do. + // Eg. requesting script source for version `^1.3.0`. + if (moduleVersion.startsWith('^') && semver.satisfies(supportedVersionOfQgrid, moduleVersion)) { + return false; + } + } catch { + return false; + } + errorDispatcher({ moduleName: widgetSource.moduleName, moduleVersion }); +} diff --git a/src/datascience-ui/native-editor/redux/reducers/index.ts b/src/datascience-ui/native-editor/redux/reducers/index.ts index df46f5817df9..729f592324e6 100644 --- a/src/datascience-ui/native-editor/redux/reducers/index.ts +++ b/src/datascience-ui/native-editor/redux/reducers/index.ts @@ -61,6 +61,7 @@ export const reducerMap: Partial = { [CommonActionType.UNMOUNT]: Creation.unmount, [CommonActionType.LOAD_IPYWIDGET_CLASS_SUCCESS]: CommonEffects.handleLoadIPyWidgetClassSuccess, [CommonActionType.LOAD_IPYWIDGET_CLASS_FAILURE]: CommonEffects.handleLoadIPyWidgetClassFailure, + [CommonActionType.IPYWIDGET_WIDGET_VERSION_NOT_SUPPORTED]: CommonEffects.notifyAboutUnsupportedWidgetVersions, // Messages from the webview (some are ignored) [InteractiveWindowMessages.StartCell]: Creation.startCell, diff --git a/src/test/datascience/ipywidgets/incompatibleWidgetHandler.unit.test.ts b/src/test/datascience/ipywidgets/incompatibleWidgetHandler.unit.test.ts new file mode 100644 index 000000000000..48f8c2170fda --- /dev/null +++ b/src/test/datascience/ipywidgets/incompatibleWidgetHandler.unit.test.ts @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +import { assert } from 'chai'; +import { warnAboutWidgetVersionsThatAreNotSupported } from '../../../datascience-ui/ipywidgets/incompatibleWidgetHandler'; + +// tslint:disable: max-func-body-length no-any +suite('Data Science - Incompatible Widgets', () => { + suite('Using qgrid widget with CDN turned on', () => { + async function testLoadingQgrid(versionToLoad: string, warningExpectedToBeDisplayed: boolean) { + let warningDisplayed = false; + warnAboutWidgetVersionsThatAreNotSupported( + { moduleName: 'qgrid' }, + versionToLoad, + true, + () => (warningDisplayed = true) + ); + + assert.equal(warningDisplayed, warningExpectedToBeDisplayed); + } + test('Widget script is not found for qgrid@1.1.0, then do not display a warning', async () => { + // This test just ensures we never display warnings for 1.1.0. + // This will never happen as the file exists on CDN. + // Hence gurantees that we'll not display when not required. + await testLoadingQgrid('1.1.0', false); + }); + test('Widget script is not found for qgrid@1.1.1, then do not display a warning', async () => { + // This test just ensures we never display warnings for 1.1.0. + // This will never happen as the file exists on CDN. + // Hence gurantees that we'll not display when not required. + await testLoadingQgrid('1.1.1', false); + }); + test('Widget script is not found for qgrid@1.1.2, then display a warning', async () => { + // We know there are no scripts on CDN for > 1.1.1 + await testLoadingQgrid('1.1.2', true); + }); + test('Widget script is not found for qgrid@^1.1.2, then display a warning', async () => { + // We know there are no scripts on CDN for > 1.1.1 + await testLoadingQgrid('^1.1.2', true); + }); + test('Widget script is not found for qgrid@1.3.0, then display a warning', async () => { + // We know there are no scripts on CDN for > 1.1.1 + await testLoadingQgrid('1.3.0', true); + }); + test('Widget script is not found for qgrid@^1.3.0, then display a warning', async () => { + // We know there are no scripts on CDN for > 1.1.1 + await testLoadingQgrid('^1.3.0', true); + }); + }); +}); From 4a62906e8cd9382b4f8c3f437756452762f50fbe Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Mon, 20 Apr 2020 14:37:22 -0700 Subject: [PATCH 2/2] Add news entry --- news/2 Fixes/11245.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/2 Fixes/11245.md diff --git a/news/2 Fixes/11245.md b/news/2 Fixes/11245.md new file mode 100644 index 000000000000..e15d31a3a9ce --- /dev/null +++ b/news/2 Fixes/11245.md @@ -0,0 +1 @@ +Warn when using a version of the widget `qgrid` greater than `1.1.1` with the recommendation to downgrade to `1.1.1`.