@eclipse-scout/core
Version:
Eclipse Scout runtime
286 lines (234 loc) • 9.81 kB
text/typescript
/*
* Copyright (c) 2010, 2025 BSI Business Systems Integration AG
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
import {
AdapterData, App, arrays, Desktop, FullModelOf, HtmlEnvironment, InitModelOf, JsonErrorResponse, ModelAdapter, ModelOf, ObjectIdProvider, PermissionCollectionType, RemoteEvent, RemoteRequest, RemoteResponse, scout, Session,
SessionStartupResponse, uiNotifications, Widget, WidgetModel
} from '../index';
import {jasmineScoutMatchers, JasmineScoutUtil, LocaleSpecHelper, SpecUiPreferencesStore, TestingApp, UiNotificationsMock} from './index';
import 'jasmine-jquery';
import $ from 'jquery';
declare global {
export class SandboxSession extends Session {
override _processEvents(events: RemoteEvent[]);
override _requestToJson(request: RemoteRequest): string;
override _processSuccessResponse(message: RemoteResponse);
override _copyAdapterData(adapterData: Record<string, AdapterData>);
override _processStartupResponse(data: SessionStartupResponse);
override _resumeBackgroundJobPolling();
override _processErrorJsonResponse(jsonError: JsonErrorResponse);
override _processErrorResponse(jqXHR: JQuery.jqXHR, textStatus: JQuery.Ajax.ErrorTextStatus, errorThrown: string, request: RemoteRequest);
}
function sandboxSession(options?: SandboxSessionOptions & ModelOf<Session>): SandboxSession;
function linkWidgetAndAdapter(widget: Widget, adapterClass: (new() => ModelAdapter) | string);
function mapAdapterData(adapterDataArray: AdapterData | WidgetModel | (AdapterData | WidgetModel)[]): Record<string, AdapterData>;
function registerAdapterData(adapterDataArray: AdapterData | WidgetModel | (AdapterData | WidgetModel)[], session: SandboxSession): void;
function removePopups(session: Session, cssClass?: string): void;
function createSimpleModel<O>(objectType: new(model?: any) => O, session: Session, id?: string): FullModelOf<O> & { objectType: new(model?: any) => O; id: string; session: Session; parent: Widget };
function createSimpleModel(objectType: string, session: Session, id?: string): { objectType: string; id: string; session: Session; parent: Widget };
function mostRecentJsonRequest(): RemoteRequest;
function sandboxDesktop();
function sendQueuedAjaxCalls(response?: JasmineAjaxResponse, time?: number);
function receiveResponseForAjaxCall(request: JasmineAjaxRequest, response?: JasmineAjaxResponse);
function uninstallUnloadHandlers(session: Session);
function createPropertyChangeEvent(model: { id: string }, properties: object);
function sleep(duration?: number): JQuery.Promise<void>;
}
export interface SandboxSessionOptions {
desktop?: ModelOf<Desktop>;
renderDesktop?: boolean;
}
window.sandboxSession = options => {
options = options || {} as ModelOf<Session>;
let $sandbox = $('#sandbox')
.addClass('scout');
let model = options as InitModelOf<Session>;
model.portletPartId = options.portletPartId || '0';
model.backgroundJobPollingEnabled = false;
model.suppressErrors = true;
model.$entryPoint = $sandbox;
let session = scout.create(Session, model) as SandboxSession;
$sandbox.data('sandboxSession', session);
// Install non-filtering requestToJson() function. This is required to test
// the value of the "showBusyIndicator" using toContainEvents(). Usually, this
// flag is filtered from the request before sending the AJAX call, however in
// the tests we want to keep it.
session._requestToJson = request => JSON.stringify(request);
// Simulate successful session initialization
session.uiSessionId = '1.1';
session.modelAdapterRegistry[session.uiSessionId] = session;
session.locale = new LocaleSpecHelper().createLocale('de-CH');
let desktop = (options.desktop || {}) as InitModelOf<Desktop>;
desktop.navigationVisible = scout.nvl(desktop.navigationVisible, false);
desktop.headerVisible = scout.nvl(desktop.headerVisible, false);
desktop.benchVisible = scout.nvl(desktop.benchVisible, false);
desktop.parent = scout.nvl(desktop.parent, session.root);
session.desktop = scout.create(Desktop, desktop);
if (scout.nvl(options.renderDesktop, true)) {
session._renderDesktop();
}
// Prevent exception when test window gets resized
$sandbox.window().off('resize', session.desktop._resizeHandler);
return session;
};
/**
* This function links and existing widget with a new adapter instance. This is useful for tests
* where you have an existing widget and later create a new adapter instance to that widget.
*/
window.linkWidgetAndAdapter = (widget, adapterClass) => {
let session = widget.session;
let adapter = scout.create(adapterClass, {
id: widget.id,
session: session
});
adapter.widget = widget;
widget.modelAdapter = adapter;
adapter._attachWidget();
adapter._postCreateWidget();
};
/**
* Converts the given adapterDataArray into a map of adapterData where the key
* is the adapterData.id and the value is the adapterData itself.
*/
window.mapAdapterData = adapterDataArray => {
let adapterDataMap = {};
adapterDataArray = arrays.ensure(adapterDataArray);
adapterDataArray.forEach(adapterData => {
adapterDataMap[adapterData.id] = adapterData;
});
return adapterDataMap;
};
/**
* Converts the given adapterDataArray into a map of adapterData and registers the adapterData in the Session.
* Only use this function when your tests requires to have a remote adapter. In that case create widget and
* remote adapter with Session#getOrCreateWidget().
*/
window.registerAdapterData = (adapterDataArray, session) => {
let adapterDataMap = window.mapAdapterData(adapterDataArray);
session._copyAdapterData(adapterDataMap);
};
/**
* Removes all open popups for the given session.
* May be used to make sure handlers get properly detached
*/
window.removePopups = (session, cssClass) => {
cssClass = cssClass || '.popup';
session.$entryPoint.children(cssClass).each(function() {
let popup = scout.widget($(this));
popup.animateRemoval = false;
popup.remove();
});
};
window.createSimpleModel = <T>(objectType, session, id) => {
if (id === undefined) {
id = ObjectIdProvider.get().createUiSeqId();
}
let parent = session.desktop;
return {
id: id,
objectType: objectType,
parent: parent,
session: session
};
};
window.mostRecentJsonRequest = () => {
let req = jasmine.Ajax.requests.mostRecent();
if (req) {
return JSON.parse(req.params);
}
};
window.sandboxDesktop = () => {
let $sandbox = sandbox() as unknown as JQuery;
$sandbox.addClass('scout desktop');
return $sandbox;
};
/**
* Sends the queued requests and simulates a response as well.
* @param response if not set an empty success response will be generated
*/
window.sendQueuedAjaxCalls = (response, time) => {
time = time || 0;
jasmine.clock().tick(time);
window.receiveResponseForAjaxCall(null, response);
};
window.receiveResponseForAjaxCall = (request, response) => {
if (!response) {
response = {
status: 200,
responseText: '{"events":[]}'
};
}
if (!request) {
request = jasmine.Ajax.requests.mostRecent();
}
if (request && request.onload) {
request.respondWith(response);
}
};
/**
* Uninstalls 'beforeunload' and 'unload' events from window that were previously installed by session.start()
*/
window.uninstallUnloadHandlers = session => {
$(window)
.off('beforeunload.' + session.uiSessionId)
.off('unload.' + session.uiSessionId);
};
window.createPropertyChangeEvent = (model, properties) => ({
target: model.id,
properties: properties,
type: 'property'
});
window.sleep = duration => {
let deferred = $.Deferred();
setTimeout(() => deferred.resolve(), duration);
return deferred.promise();
};
export const JasmineScout = {
runTestSuite(context) {
this.startApp(TestingApp);
beforeAll(() => {
spyOn(scout, 'reloadPage').and.callFake(() => {
// NOP: disable reloading as this would restart the whole test-suite again and again
});
});
beforeEach(() => {
jasmine.addMatchers(jasmineScoutMatchers);
SpecUiPreferencesStore.install();
});
afterEach(() => {
const $sandbox = $('#sandbox');
const session = $sandbox.data('sandboxSession');
$sandbox.removeData('sandboxSession');
if (session?.layoutValidator) {
(session.layoutValidator as { _postValidateFunctions: (() => void)[] })._postValidateFunctions = [];
session.layoutValidator.desktop = null;
}
// Cleanup global objects and remove every handler to avoid a memory leak because widgets are not destroyed properly after tests, so they won't unregister their handlers
HtmlEnvironment.get().off('propertyChange');
uiNotifications.tearDown();
SpecUiPreferencesStore.uninstall();
});
context.keys().forEach(context);
},
startApp(AppClass: new() => App) {
// App initialization uses promises which are executed asynchronously
// -> Use the clock to make sure all promise callbacks are executed before any test starts.
jasmine.clock().install();
jasmine.Ajax.install();
App.addListener('prepare', () => {
JasmineScoutUtil.mockRestCall('api/permissions', {type: PermissionCollectionType.ALL});
JasmineScoutUtil.mockRestCall('api/codes', {});
UiNotificationsMock.register(); // Disable endless unsuccessful polling in specs if a component subscribes for ui notifications
});
new AppClass().init();
jasmine.clock().tick(1000);
jasmine.Ajax.uninstall();
jasmine.clock().uninstall();
}
};