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`.
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);
+ });
+ });
+});