UNPKG

@eclipse-scout/core

Version:
244 lines (217 loc) 8.61 kB
/* * 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 { AbstractConstructor, arrays, AutoLeafPageWithNodes, BaseDoEntity, Constructor, dataObjects, DoEntity, HybridActionEvent, HybridManager, ObjectFactory, Page, PageWithNodes, PageWithTable, scout, Session, strings, TypeDescriptor, Widget } from '../index'; import $ from 'jquery'; import 'jasmine-ajax'; let _jsonResourceCache = {}; /** * Utility functions for jasmine tests. */ export const JasmineScoutUtil = { /** * @returns the loaded JSON data structure */ loadJsonResource(jsonResourceUrl: string, options: { useCache?: boolean } = {}): JQuery.Promise<any> { scout.assertParameter('jsonResourceUrl', jsonResourceUrl); if (scout.nvl(options.useCache, true)) { let json = _jsonResourceCache[jsonResourceUrl]; if (json) { return $.resolvedPromise(json); } } return $.ajax({ async: false, method: 'GET', dataType: 'json', contentType: 'application/json; charset=UTF-8', cache: false, url: jsonResourceUrl }) .done(json => { if (scout.nvl(options.useCache, true)) { _jsonResourceCache[jsonResourceUrl] = json; } return $.resolvedPromise(json); }) .fail((jqXHR, textStatus, errorThrown) => { throw new Error('Could not load resource from url: ' + jsonResourceUrl); }); }, loadJsonResourceAndMockRestCall(resourceUrlToMock: string, jsonResourceUrl: string, options: { useCache?: boolean; restriction?: any; method?: string; } = {}) { scout.assertParameter('resourceUrlToMock', resourceUrlToMock); JasmineScoutUtil.loadJsonResource(jsonResourceUrl, options) .then(json => JasmineScoutUtil.mockRestCall(resourceUrlToMock, json, options)); }, mockRestLookupCall(resourceUrlToMock: string, lookupRows: any[], parentRestriction?: any) { scout.assertParameter('resourceUrlToMock', resourceUrlToMock); // Normalize lookup rows lookupRows = arrays.ensure(lookupRows).map(lookupRow => $.extend({ active: true, enabled: true, parentId: null }, lookupRow)); // getAll() JasmineScoutUtil.mockRestCall(resourceUrlToMock, { rows: lookupRows }, { restriction: parentRestriction }); // getKey() lookupRows.forEach(lookupRow => { JasmineScoutUtil.mockRestCall(resourceUrlToMock, { rows: [lookupRow] }, { restriction: lookupRow.id }); }); }, mockRestCall(resourceUrlToMock: string, responseData: any, options: { restriction?: any; method?: string; /** * Used to serialize the responseData. Default is {@link JSON.stringify}. */ stringify?: (any) => string; } = {}) { let url = new RegExp('.*' + strings.quote(resourceUrlToMock) + '.*'); let data = options.restriction ? new RegExp('.*' + strings.quote(options.restriction) + '.*') : undefined; const stringify = options.stringify || JSON.stringify; const responseText = stringify(responseData); jasmine.Ajax.stubRequest(url, data, options.method).andReturn({ status: 200, responseText }); }, mockDataObjectRestCall(resourceUrlToMock: string, responseData: BaseDoEntity | void, options: { restriction?: any; method?: string; /** * Used to serialize the responseData. Default is {@link dataObjects.stringify}. */ stringify?: (any) => string; } = {}) { options.stringify = options.stringify || dataObjects.stringify; this.mockRestCall(resourceUrlToMock, responseData, options); }, /** * If an ajax call is not mocked, this fallback will be triggered to show information about which url is not mocked. */ captureNotMockedCalls() { jasmine.Ajax.stubRequest(/.*/).andCallFunction((request: JasmineAjaxRequest) => { fail('Ajax call not mocked for url: ' + request.url + ', method: ' + request.method); }); }, /** * Calls the given mock as soon as a hybrid action with the given actionType is called. * The mock is called asynchronously using setTimeout to let the runtime code add any required event listeners first. * * The mock may return an object with [id, widget] if the action is supposed to create widgets. * The format of the id depends on the method used to add widgets: * - `AbstractHybridAction.addWidget(IWidget)` (e.g. `AbstractFormHybridAction`): `${widgetId}` * - `AbstractHybridAction.addWidgets(Map<String, IWidget>)`: `${actionId}${widgetId}` */ mockHybridAction<TData extends DoEntity>(session: Session, actionType: string, mock: (event: HybridActionEvent<TData>) => Record<string, Widget>) { let hm = HybridManager.get(session); hm.on('hybridAction', (event: HybridActionEvent<TData>) => { if (event.data.actionType === actionType) { setTimeout(() => { let widgets = mock(event); if (widgets) { hm.setProperty('widgets', widgets); } }); } }); }, /** * Asserts that every page has an uuid and a specific {@link PageParamDo}, if required. */ assertPageCompleteness(options?: PageCompletenessOptions) { options = options || {}; let pagesNotRequiringUuid: Set<Constructor<Page> | AbstractConstructor<Page>> = new Set([PageWithNodes, PageWithTable, AutoLeafPageWithNodes, ...options.pagesNotRequiringUuid || []]); let pagesNotRequiringPageParam: Set<Constructor<Page> | AbstractConstructor<Page>> = new Set([PageWithNodes, PageWithTable, AutoLeafPageWithNodes, ...options.pagesNotRequiringPageParam || []]); let missingUuids: Set<string> = new Set(); let missingPageParams = new Set(); let completePages = new Set(); for (const PageConstructor of ObjectFactory.get().getSubClassesOf(Page)) { let pageType = ObjectFactory.get().getObjectType(PageConstructor); if (options.namespace && !pageType.startsWith(options.namespace)) { continue; } let page = new PageConstructor(); page.minimalInit(); // Assert uuid if (scout.nvl(options.assertUuid, true) && !page.uuid && !pagesNotRequiringUuid.has(PageConstructor)) { missingUuids.add(pageType); } // Assert pageParam if (scout.nvl(options.assertPageParam, true)) { let pageParamType = `${pageType}ParamDo`; let PageParam = TypeDescriptor.resolveType(pageParamType); if (!PageParam && !pagesNotRequiringPageParam.has(PageConstructor)) { missingPageParams.add(pageType); } } if (!missingUuids.has(pageType) && !missingPageParams.has(pageType)) { completePages.add(pageType); } } if (missingUuids.size > 0) { fail([ `Found ${missingUuids.size} pages without a uuid. Please ensure every page has a uuid.`, ...missingUuids ].join('\n')); } if (missingPageParams.size > 0) { fail([ `Found ${missingPageParams.size} pages without a pageParam.`, 'If a pageParam is required, create one and add `declare pageParam: NewPageParam` to your page.', 'Otherwise, add the page to the ignore list (`options.pagesNotRequiringPageParam`).', ...missingPageParams ].join('\n')); } if (completePages.size > 0) { console.log(`PageCompleteness: the following pages are complete: ${Array.from(completePages).join(', ')}`); } if (completePages.size === 0 && missingUuids.size === 0 && missingPageParams.size === 0) { console.log('PageCompleteness: no pages found in this module.'); } // A test without an expectation logs a warning expect(true).toBe(true); } }; export type PageCompletenessOptions = { /** * Specifies whether the pages need an uuid. Default is true. */ assertUuid?: boolean; /** * Specifies whether the pages need a pageParam. Default is true. */ assertPageParam?: boolean; /** * Contains the pages that do not require an uuid. */ pagesNotRequiringUuid?: (Constructor<Page> | AbstractConstructor<Page>)[]; /** * Contains the pages that do not require a pageParam, e.g. because the page does not have any parameters. */ pagesNotRequiringPageParam?: (Constructor<Page> | AbstractConstructor<Page>)[]; /** * If specified, only the pages in this namespace are considered. */ namespace?: string; };