diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 11:59:07 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 11:59:07 +0000 |
commit | 8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca (patch) | |
tree | 544930fb309b30317ae9797a9683768705d664c4 /spec/frontend/editor | |
parent | 4b1de649d0168371549608993deac953eb692019 (diff) | |
download | gitlab-ce-8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca.tar.gz |
Add latest changes from gitlab-org/gitlab@13-7-stable-eev13.7.0-rc42
Diffstat (limited to 'spec/frontend/editor')
-rw-r--r-- | spec/frontend/editor/editor_lite_extension_base_spec.js | 44 | ||||
-rw-r--r-- | spec/frontend/editor/editor_lite_spec.js | 159 | ||||
-rw-r--r-- | spec/frontend/editor/editor_markdown_ext_spec.js | 4 |
3 files changed, 169 insertions, 38 deletions
diff --git a/spec/frontend/editor/editor_lite_extension_base_spec.js b/spec/frontend/editor/editor_lite_extension_base_spec.js new file mode 100644 index 00000000000..ff53640b096 --- /dev/null +++ b/spec/frontend/editor/editor_lite_extension_base_spec.js @@ -0,0 +1,44 @@ +import { ERROR_INSTANCE_REQUIRED_FOR_EXTENSION } from '~/editor/constants'; +import { EditorLiteExtension } from '~/editor/editor_lite_extension_base'; + +describe('The basis for an Editor Lite extension', () => { + let ext; + const defaultOptions = { foo: 'bar' }; + + it.each` + description | instance | options + ${'accepts configuration options and instance'} | ${{}} | ${defaultOptions} + ${'leaves instance intact if no options are passed'} | ${{}} | ${undefined} + ${'does not fail if both instance and the options are omitted'} | ${undefined} | ${undefined} + ${'throws if only options are passed'} | ${undefined} | ${defaultOptions} + `('$description', ({ instance, options } = {}) => { + const originalInstance = { ...instance }; + + if (instance) { + if (options) { + Object.entries(options).forEach(prop => { + expect(instance[prop]).toBeUndefined(); + }); + // Both instance and options are passed + ext = new EditorLiteExtension({ instance, ...options }); + Object.entries(options).forEach(([prop, value]) => { + expect(ext[prop]).toBeUndefined(); + expect(instance[prop]).toBe(value); + }); + } else { + ext = new EditorLiteExtension({ instance }); + expect(instance).toEqual(originalInstance); + } + } else if (options) { + // Options are passed without instance + expect(() => { + ext = new EditorLiteExtension({ ...options }); + }).toThrow(ERROR_INSTANCE_REQUIRED_FOR_EXTENSION); + } else { + // Neither options nor instance are passed + expect(() => { + ext = new EditorLiteExtension(); + }).not.toThrow(); + } + }); +}); diff --git a/spec/frontend/editor/editor_lite_spec.js b/spec/frontend/editor/editor_lite_spec.js index 2968984df01..3a7680f6d17 100644 --- a/spec/frontend/editor/editor_lite_spec.js +++ b/spec/frontend/editor/editor_lite_spec.js @@ -1,6 +1,8 @@ +/* eslint-disable max-classes-per-file */ import { editor as monacoEditor, languages as monacoLanguages, Uri } from 'monaco-editor'; import waitForPromises from 'helpers/wait_for_promises'; import Editor from '~/editor/editor_lite'; +import { EditorLiteExtension } from '~/editor/editor_lite_extension_base'; import { DEFAULT_THEME, themes } from '~/ide/lib/themes'; import { EDITOR_LITE_INSTANCE_ERROR_NO_EL, URI_PREFIX } from '~/editor/constants'; @@ -242,17 +244,53 @@ describe('Base editor', () => { describe('extensions', () => { let instance; - const foo1 = jest.fn(); - const foo2 = jest.fn(); - const bar = jest.fn(); - const MyExt1 = { - foo: foo1, + const alphaRes = jest.fn(); + const betaRes = jest.fn(); + const fooRes = jest.fn(); + const barRes = jest.fn(); + class AlphaClass { + constructor() { + this.res = alphaRes; + } + alpha() { + return this?.nonExistentProp || alphaRes; + } + } + class BetaClass { + beta() { + return this?.nonExistentProp || betaRes; + } + } + class WithStaticMethod { + constructor({ instance: inst, ...options } = {}) { + Object.assign(inst, options); + } + static computeBoo(a) { + return a + 1; + } + boo() { + return WithStaticMethod.computeBoo(this.base); + } + } + class WithStaticMethodExtended extends EditorLiteExtension { + static computeBoo(a) { + return a + 1; + } + boo() { + return WithStaticMethodExtended.computeBoo(this.base); + } + } + const AlphaExt = new AlphaClass(); + const BetaExt = new BetaClass(); + const FooObjExt = { + foo() { + return fooRes; + }, }; - const MyExt2 = { - bar, - }; - const MyExt3 = { - foo: foo2, + const BarObjExt = { + bar() { + return barRes; + }, }; describe('basic functionality', () => { @@ -260,13 +298,6 @@ describe('Base editor', () => { instance = editor.createInstance({ el: editorEl, blobPath, blobContent }); }); - it('is extensible with the extensions', () => { - expect(instance.foo).toBeUndefined(); - - instance.use(MyExt1); - expect(instance.foo).toEqual(foo1); - }); - it('does not fail if no extensions supplied', () => { const spy = jest.spyOn(global.console, 'error'); instance.use(); @@ -274,24 +305,80 @@ describe('Base editor', () => { expect(spy).not.toHaveBeenCalled(); }); - it('is extensible with multiple extensions', () => { - expect(instance.foo).toBeUndefined(); - expect(instance.bar).toBeUndefined(); + it("does not extend instance with extension's constructor", () => { + expect(instance.constructor).toBeDefined(); + const { constructor } = instance; + + expect(AlphaExt.constructor).toBeDefined(); + expect(AlphaExt.constructor).not.toEqual(constructor); + + instance.use(AlphaExt); + expect(instance.constructor).toBe(constructor); + }); + + it.each` + type | extensions | methods | expectations + ${'ES6 classes'} | ${AlphaExt} | ${['alpha']} | ${[alphaRes]} + ${'multiple ES6 classes'} | ${[AlphaExt, BetaExt]} | ${['alpha', 'beta']} | ${[alphaRes, betaRes]} + ${'simple objects'} | ${FooObjExt} | ${['foo']} | ${[fooRes]} + ${'multiple simple objects'} | ${[FooObjExt, BarObjExt]} | ${['foo', 'bar']} | ${[fooRes, barRes]} + ${'combination of ES6 classes and objects'} | ${[AlphaExt, BarObjExt]} | ${['alpha', 'bar']} | ${[alphaRes, barRes]} + `('is extensible with $type', ({ extensions, methods, expectations } = {}) => { + methods.forEach(method => { + expect(instance[method]).toBeUndefined(); + }); - instance.use([MyExt1, MyExt2]); + instance.use(extensions); - expect(instance.foo).toEqual(foo1); - expect(instance.bar).toEqual(bar); + methods.forEach(method => { + expect(instance[method]).toBeDefined(); + }); + + expectations.forEach((expectation, i) => { + expect(instance[methods[i]].call()).toEqual(expectation); + }); }); + it('does not extend instance with private data of an extension', () => { + const ext = new WithStaticMethod({ instance }); + ext.staticMethod = () => { + return 'foo'; + }; + ext.staticProp = 'bar'; + + expect(instance.boo).toBeUndefined(); + expect(instance.staticMethod).toBeUndefined(); + expect(instance.staticProp).toBeUndefined(); + + instance.use(ext); + + expect(instance.boo).toBeDefined(); + expect(instance.staticMethod).toBeUndefined(); + expect(instance.staticProp).toBeUndefined(); + }); + + it.each([WithStaticMethod, WithStaticMethodExtended])( + 'properly resolves data for an extension with private data', + ExtClass => { + const base = 1; + expect(instance.base).toBeUndefined(); + expect(instance.boo).toBeUndefined(); + + const ext = new ExtClass({ instance, base }); + + instance.use(ext); + expect(instance.base).toBe(1); + expect(instance.boo()).toBe(2); + }, + ); + it('uses the last definition of a method in case of an overlap', () => { - instance.use([MyExt1, MyExt2, MyExt3]); - expect(instance).toEqual( - expect.objectContaining({ - foo: foo2, - bar, - }), - ); + const FooObjExt2 = { foo: 'foo2' }; + instance.use([FooObjExt, BarObjExt, FooObjExt2]); + expect(instance).toMatchObject({ + foo: 'foo2', + ...BarObjExt, + }); }); it('correctly resolves references withing extensions', () => { @@ -396,15 +483,15 @@ describe('Base editor', () => { }); it('extends all instances if no specific instance is passed', () => { - editor.use(MyExt1); - expect(inst1.foo).toEqual(foo1); - expect(inst2.foo).toEqual(foo1); + editor.use(AlphaExt); + expect(inst1.alpha()).toEqual(alphaRes); + expect(inst2.alpha()).toEqual(alphaRes); }); it('extends specific instance if it has been passed', () => { - editor.use(MyExt1, inst2); - expect(inst1.foo).toBeUndefined(); - expect(inst2.foo).toEqual(foo1); + editor.use(AlphaExt, inst2); + expect(inst1.alpha).toBeUndefined(); + expect(inst2.alpha()).toEqual(alphaRes); }); }); }); diff --git a/spec/frontend/editor/editor_markdown_ext_spec.js b/spec/frontend/editor/editor_markdown_ext_spec.js index 30ab29aad35..b432d4d66ad 100644 --- a/spec/frontend/editor/editor_markdown_ext_spec.js +++ b/spec/frontend/editor/editor_markdown_ext_spec.js @@ -1,6 +1,6 @@ import { Range, Position } from 'monaco-editor'; import EditorLite from '~/editor/editor_lite'; -import EditorMarkdownExtension from '~/editor/editor_markdown_ext'; +import { EditorMarkdownExtension } from '~/editor/editor_markdown_ext'; describe('Markdown Extension for Editor Lite', () => { let editor; @@ -31,7 +31,7 @@ describe('Markdown Extension for Editor Lite', () => { blobPath: filePath, blobContent: text, }); - editor.use(EditorMarkdownExtension); + editor.use(new EditorMarkdownExtension()); }); afterEach(() => { |