UNPKG

@theia/core

Version:

Theia is a cloud & desktop IDE framework implemented in TypeScript.

338 lines • 18.1 kB
"use strict"; // ***************************************************************************** // Copyright (C) 2018 Ericsson and others. // // This program and the accompanying materials are made available under the // terms of the Eclipse Public License v. 2.0 which is available at // http://www.eclipse.org/legal/epl-2.0. // // This Source Code may also be made available under the following Secondary // Licenses when the conditions for such availability set forth in the Eclipse // Public License v. 2.0 are satisfied: GNU General Public License, version 2 // with the GNU Classpath Exception which is available at // https://www.gnu.org/software/classpath/license.html. // // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 // ***************************************************************************** Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-disable @typescript-eslint/no-explicit-any */ const jsdom_1 = require("../test/jsdom"); let disableJSDOM = (0, jsdom_1.enableJSDOM)(); const assert = require("assert"); const inversify_1 = require("inversify"); const frontend_application_bindings_1 = require("../frontend-application-bindings"); const test_1 = require("./test"); const preference_service_1 = require("./preference-service"); const preference_contribution_1 = require("./preference-contribution"); const preference_scope_1 = require("./preference-scope"); const preference_provider_1 = require("./preference-provider"); const frontend_application_config_provider_1 = require("../frontend-application-config-provider"); const preference_proxy_1 = require("./preference-proxy"); const injectable_preference_proxy_1 = require("./injectable-preference-proxy"); const promise_util_1 = require("../../common/promise-util"); disableJSDOM(); process.on('unhandledRejection', (reason, promise) => { console.error(reason); throw reason; }); const chai_1 = require("chai"); let testContainer; function createTestContainer() { const result = new inversify_1.Container(); (0, frontend_application_bindings_1.bindPreferenceService)(result.bind.bind(result)); (0, test_1.bindMockPreferenceProviders)(result.bind.bind(result), result.unbind.bind(result)); return result; } describe('Preference Proxy', () => { let prefService; let prefSchema; before(() => { disableJSDOM = (0, jsdom_1.enableJSDOM)(); frontend_application_config_provider_1.FrontendApplicationConfigProvider.set({}); }); after(() => { disableJSDOM(); }); beforeEach(async () => { testContainer = createTestContainer(); prefSchema = testContainer.get(preference_contribution_1.PreferenceSchemaProvider); prefService = testContainer.get(preference_service_1.PreferenceService); getProvider(preference_scope_1.PreferenceScope.User).markReady(); getProvider(preference_scope_1.PreferenceScope.Workspace).markReady(); getProvider(preference_scope_1.PreferenceScope.Folder).markReady(); try { await prefService.ready; } catch (e) { console.error(e); } }); afterEach(() => { }); // Actually run the test suite with different parameters: testPreferenceProxy('Synchronous Schema Definition + createPreferenceProxy', { asyncSchema: false }); testPreferenceProxy('Asynchronous Schema Definition (1s delay) + createPreferenceProxy', { asyncSchema: true }); testPreferenceProxy('Synchronous Schema Definition + Injectable Preference Proxy', { asyncSchema: false, useFactory: true }); testPreferenceProxy('Asynchronous Schema Definition (1s delay) + Injectable Preference Proxy', { asyncSchema: true, useFactory: true }); function getProvider(scope) { return testContainer.getNamed(preference_provider_1.PreferenceProvider, scope); } function testPreferenceProxy(testDescription, testOptions) { describe(testDescription, () => { function getProxy(schema, options) { const s = schema || { properties: { 'my.pref': { type: 'string', defaultValue: 'foo' } } }; if (testOptions.asyncSchema) { const promisedSchema = new Promise(resolve => setTimeout(() => { prefSchema.setSchema(s); resolve(s); }, 1000)); const proxy = testOptions.useFactory ? testContainer.get(injectable_preference_proxy_1.PreferenceProxyFactory)(promisedSchema, options) : (0, preference_proxy_1.createPreferenceProxy)(prefService, promisedSchema, options); return { proxy, promisedSchema }; } else { prefSchema.setSchema(s); const proxy = testOptions.useFactory ? testContainer.get(injectable_preference_proxy_1.PreferenceProxyFactory)(s, options) : (0, preference_proxy_1.createPreferenceProxy)(prefService, s, options); return { proxy }; } } if (testOptions.asyncSchema) { it('using the proxy before the schema is set should be no-op', async () => { const { proxy, promisedSchema } = getProxy(); let changed = 0; proxy.onPreferenceChanged(event => { changed += 1; }); (0, chai_1.expect)(proxy['my.pref']).to.equal(undefined); (0, chai_1.expect)(Object.keys(proxy).length).to.equal(0); // The proxy doesn't know the schema, so events shouldn't be forwarded: await getProvider(preference_scope_1.PreferenceScope.User).setPreference('my.pref', 'bar'); (0, chai_1.expect)(changed).to.equal(0); (0, chai_1.expect)(proxy['my.pref']).to.equal(undefined); (0, chai_1.expect)(Object.keys(proxy).length).to.equal(0); // Once the schema is resolved, operations should be working: await promisedSchema; (0, chai_1.expect)(proxy['my.pref']).to.equal('bar'); (0, chai_1.expect)(Object.keys(proxy)).members(['my.pref']); await getProvider(preference_scope_1.PreferenceScope.User).setPreference('my.pref', 'fizz'); (0, chai_1.expect)(changed).to.equal(1); (0, chai_1.expect)(proxy['my.pref']).to.equal('fizz'); }); } it('by default, it should provide access in flat style but not deep', async () => { const { proxy, promisedSchema } = getProxy(); if (promisedSchema) { await promisedSchema; } (0, chai_1.expect)(proxy['my.pref']).to.equal('foo'); (0, chai_1.expect)(proxy.my).to.equal(undefined); (0, chai_1.expect)(Object.keys(proxy).join()).to.equal(['my.pref'].join()); }); it('it should provide access in deep style but not flat', async () => { const { proxy, promisedSchema } = getProxy(undefined, { style: 'deep' }); if (promisedSchema) { await promisedSchema; } (0, chai_1.expect)(proxy['my.pref']).to.equal(undefined); (0, chai_1.expect)(proxy.my.pref).to.equal('foo'); (0, chai_1.expect)(Object.keys(proxy).join()).equal('my'); }); it('it should provide access in to both styles', async () => { const { proxy, promisedSchema } = getProxy(undefined, { style: 'both' }); if (promisedSchema) { await promisedSchema; } (0, chai_1.expect)(proxy['my.pref']).to.equal('foo'); (0, chai_1.expect)(proxy.my.pref).to.equal('foo'); (0, chai_1.expect)(Object.keys(proxy).join()).to.equal(['my', 'my.pref'].join()); }); it('it should forward change events', async () => { const { proxy, promisedSchema } = getProxy(undefined, { style: 'both' }); if (promisedSchema) { await promisedSchema; } let theChange; proxy.onPreferenceChanged(change => { (0, chai_1.expect)(theChange).to.equal(undefined); theChange = change; }); let theSecondChange; proxy.my.onPreferenceChanged(change => { (0, chai_1.expect)(theSecondChange).to.equal(undefined); theSecondChange = change; }); await getProvider(preference_scope_1.PreferenceScope.User).setPreference('my.pref', 'bar'); (0, chai_1.expect)(theChange.newValue).to.equal('bar'); (0, chai_1.expect)(theChange.oldValue).to.equal(undefined); (0, chai_1.expect)(theChange.preferenceName).to.equal('my.pref'); (0, chai_1.expect)(theSecondChange.newValue).to.equal('bar'); (0, chai_1.expect)(theSecondChange.oldValue).to.equal(undefined); (0, chai_1.expect)(theSecondChange.preferenceName).to.equal('my.pref'); }); it("should not forward changes that don't match the proxy's language override", async () => { const { proxy, promisedSchema } = getProxy({ properties: { 'my.pref': { type: 'string', defaultValue: 'foo', overridable: true, } } }, { style: 'both', overrideIdentifier: 'typescript' }); await promisedSchema; let changeEventsEmittedByProxy = 0; let changeEventsEmittedByService = 0; prefSchema.registerOverrideIdentifier('swift'); prefSchema.registerOverrideIdentifier('typescript'); // The service will emit events related to updating the overrides - those are irrelevant await (0, promise_util_1.waitForEvent)(prefService.onPreferencesChanged, 500); prefService.onPreferencesChanged(() => changeEventsEmittedByService++); proxy.onPreferenceChanged(() => changeEventsEmittedByProxy++); await prefService.set(prefService.overridePreferenceName({ overrideIdentifier: 'swift', preferenceName: 'my.pref' }), 'boo', preference_scope_1.PreferenceScope.User); (0, chai_1.expect)(changeEventsEmittedByService, 'The service should have emitted an event for the non-matching override.').to.equal(1); (0, chai_1.expect)(changeEventsEmittedByProxy, 'The proxy should not have emitted an event for the non-matching override.').to.equal(0); await prefService.set('my.pref', 'far', preference_scope_1.PreferenceScope.User); (0, chai_1.expect)(changeEventsEmittedByService, 'The service should have emitted an event for the base name.').to.equal(2); (0, chai_1.expect)(changeEventsEmittedByProxy, 'The proxy should have emitted for an event for the base name.').to.equal(1); await prefService.set(prefService.overridePreferenceName({ preferenceName: 'my.pref', overrideIdentifier: 'typescript' }), 'faz', preference_scope_1.PreferenceScope.User); (0, chai_1.expect)(changeEventsEmittedByService, 'The service should have emitted an event for the matching override.').to.equal(3); (0, chai_1.expect)(changeEventsEmittedByProxy, 'The proxy should have emitted an event for the matching override.').to.equal(2); await prefService.set('my.pref', 'yet another value', preference_scope_1.PreferenceScope.User); (0, chai_1.expect)(changeEventsEmittedByService, 'The service should have emitted another event for the base name.').to.equal(4); (0, chai_1.expect)(changeEventsEmittedByProxy, 'The proxy should not have emitted an event, because the value for TS has been overridden.').to.equal(2); }); it('`affects` should only return `true` if the language overrides match', async () => { const { proxy, promisedSchema } = getProxy({ properties: { 'my.pref': { type: 'string', defaultValue: 'foo', overridable: true, } } }, { style: 'both' }); await promisedSchema; prefSchema.registerOverrideIdentifier('swift'); prefSchema.registerOverrideIdentifier('typescript'); let changesNotAffectingTypescript = 0; let changesAffectingTypescript = 0; proxy.onPreferenceChanged(change => { if (change.affects(undefined, 'typescript')) { changesAffectingTypescript++; } else { changesNotAffectingTypescript++; } }); await prefService.set('my.pref', 'bog', preference_scope_1.PreferenceScope.User); (0, chai_1.expect)(changesNotAffectingTypescript, 'Two events (one for `my.pref` and one for `[swift].my.pref`) should not have affected TS').to.equal(2); (0, chai_1.expect)(changesAffectingTypescript, 'One event should have been fired that does affect typescript.').to.equal(1); }); it('toJSON with deep', async () => { const { proxy, promisedSchema } = getProxy({ properties: { 'foo.baz': { type: 'number', default: 4 }, 'foo.bar.x': { type: 'boolean', default: true }, 'foo.bar.y': { type: 'boolean', default: false }, 'a': { type: 'string', default: 'a' } } }, { style: 'deep' }); if (promisedSchema) { await promisedSchema; } assert.deepStrictEqual(JSON.stringify(proxy, undefined, 2), JSON.stringify({ foo: { baz: 4, bar: { x: true, y: false } }, a: 'a' }, undefined, 2), 'there should not be foo.bar.x to avoid sending excessive data to remote clients'); }); it('get nested default', async () => { const { proxy, promisedSchema } = getProxy({ properties: { 'foo': { 'anyOf': [ { 'enum': [ false ] }, { 'properties': { 'bar': { 'anyOf': [ { 'enum': [ false ] }, { 'properties': { 'x': { type: 'boolean' }, 'y': { type: 'boolean' } } } ] } } } ], default: { bar: { x: true, y: false } } } } }, { style: 'both' }); if (promisedSchema) { await promisedSchema; } assert.deepStrictEqual(proxy['foo'], { bar: { x: true, y: false } }); assert.deepStrictEqual(proxy['foo.bar'], { x: true, y: false }); assert.strictEqual(proxy['foo.bar.x'], true); assert.strictEqual(proxy['foo.bar.y'], false); }); }); } }); //# sourceMappingURL=preference-proxy.spec.js.map