From c0cdbb0801e80ec664f742d6bf21241d2fa22f16 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Fri, 6 Sep 2024 12:53:47 +1000 Subject: [PATCH 01/17] INT-3303: Convert existing test.ts files to use bdd-styling conventions. --- .vscode/settings.json | 5 + src/test/ts/alien/Loader.ts | 68 ++++---- src/test/ts/atomic/UtilsTest.ts | 17 +- src/test/ts/browser/EditorLoadTest.ts | 42 +++++ src/test/ts/browser/InitTest.ts | 174 +++++++++++--------- src/test/ts/browser/LoadTinyTest.ts | 222 ++++++++++++++------------ 6 files changed, 314 insertions(+), 214 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 src/test/ts/browser/EditorLoadTest.ts diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..306c494 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.words": [ + "asynctest" + ] +} \ No newline at end of file diff --git a/src/test/ts/alien/Loader.ts b/src/test/ts/alien/Loader.ts index ffc6529..7d9faf8 100644 --- a/src/test/ts/alien/Loader.ts +++ b/src/test/ts/alien/Loader.ts @@ -1,4 +1,3 @@ -import { Chain } from '@ephox/agar'; import { Fun } from '@ephox/katamari'; import { Attribute, SugarBody, SugarElement, Insert, Remove, SelectorFind } from '@ephox/sugar'; import Editor from 'src/main/ts/index'; @@ -19,40 +18,41 @@ const getRoot = () => SelectorFind.descendant(SugarBody.body(), '#root').getOrTh return root; }); -const cRender = (data: Record = {}, template: string = ``) => - Chain.async((_value, next, _die) => { - const root = getRoot(); - const mountPoint = SugarElement.fromTag('div'); - Insert.append(root, mountPoint); - - const originalInit = data.init || {}; - const originalSetup = originalInit.setup || Fun.noop; - - const vm = createApp({ - template, - components: { - Editor - }, - data: () => ({ - ...data, - outputFormat: 'text', - init: { - ...originalInit, - setup: (editor: any) => { - originalSetup(editor); - editor.on('SkinLoaded', () => { - setTimeout(() => { - next({ editor, vm }); - }, 0); - }); - } +const pRender = (data: Record = {}, template: string = ``): Promise => new Promise((resolve) => { + const root = getRoot(); + const mountPoint = SugarElement.fromTag('div'); + Insert.append(root, mountPoint); + + const originalInit = data.init || {}; + const originalSetup = originalInit.setup || Fun.noop; + + const vm = createApp({ + template, + components: { + Editor + }, + data: () => ({ + ...data, + outputFormat: 'text', + init: { + ...originalInit, + 'licenseKey': 'gpl', + 'api-key': 'your-api-key', + 'setup': (editor: any) => { + originalSetup(editor); + editor.on('SkinLoaded', () => { + setTimeout(() => { + resolve({ editor, vm }); + }, 0); + }); } - }), - }).mount(mountPoint.dom); - }); + } + }), + }).mount(mountPoint.dom); +}); -const cRemove = Chain.op(() => { +const remove = () => { Remove.remove(getRoot()); -}); +}; -export { cRender, cRemove }; \ No newline at end of file +export { pRender, remove, getRoot }; \ No newline at end of file diff --git a/src/test/ts/atomic/UtilsTest.ts b/src/test/ts/atomic/UtilsTest.ts index 451ba6d..067bca3 100644 --- a/src/test/ts/atomic/UtilsTest.ts +++ b/src/test/ts/atomic/UtilsTest.ts @@ -1,15 +1,20 @@ import { Assertions } from '@ephox/agar'; -import { UnitTest } from '@ephox/bedrock-client'; +import { describe, it } from '@ephox/bedrock-client'; import { isValidKey } from 'src/main/ts/Utils'; -UnitTest.test('UtilsTest', () => { - +describe('UtilsTest', () => { const checkValidKey = (key: string, expected: boolean) => { const actual = isValidKey(key); Assertions.assertEq('Key is valid', expected, actual); }; - checkValidKey('onKeyUp', true); - checkValidKey('onkeyup', true); - checkValidKey('onDisable', false); + it('should check if key is valid onKeyUp', () => { + checkValidKey('onKeyUp', true); + }); + it('should check if key is valid onkeyup', () => { + checkValidKey('onkeyup', true); + }); + it('should check if key is valid onDisable', () => { + checkValidKey('onDisable', false); + }); }); \ No newline at end of file diff --git a/src/test/ts/browser/EditorLoadTest.ts b/src/test/ts/browser/EditorLoadTest.ts new file mode 100644 index 0000000..6a82a8e --- /dev/null +++ b/src/test/ts/browser/EditorLoadTest.ts @@ -0,0 +1,42 @@ +import { Assertions, UiFinder, Waiter } from '@ephox/agar'; +import { describe, beforeEach, afterEach, it } from '@ephox/bedrock-client'; +import { Context } from 'vm'; +import { getRoot, pRender, remove } from '../alien/Loader'; + +describe('Editor Component Tests', () => { + let context: Context; + + beforeEach(async () => { + context = await pRender(); + }); + + afterEach(() => { + remove(); + }); + + it('should render the editor with the given data and template', async () => { + Assertions.assertEq('Vue instance should exist', true, !!context.vm); + Assertions.assertEq('Vue instance should have a DOM element', true, context.vm.$el instanceof window.HTMLElement); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + const textareaResult = UiFinder.findIn(context.vm.$el, 'textarea'); + textareaResult.fold( + () => Assertions.assertEq('Textarea element should exist', true, false), + () => Assertions.assertEq('Textarea element should exist', true, true) + ); + + await Waiter.pTryUntil('Wait for the editor to load the skin', () => { + Assertions.assertEq('Editor instance should exist', true, !!context.editor); + }); + }); + + it('should remove the editor component from the DOM', () => { + remove(); + const root = getRoot(); + Assertions.assertEq( + 'Root element should not contain any child nodes after removal', + true, + root.dom.childNodes.length === 0 + ); + }); +}); diff --git a/src/test/ts/browser/InitTest.ts b/src/test/ts/browser/InitTest.ts index 0be6788..041d352 100644 --- a/src/test/ts/browser/InitTest.ts +++ b/src/test/ts/browser/InitTest.ts @@ -1,83 +1,109 @@ -import { GeneralSteps, Logger, Pipeline, Assertions, Chain, Keyboard, Keys } from '@ephox/agar'; -import { UnitTest } from '@ephox/bedrock-client'; -import { VersionLoader } from '@tinymce/miniature'; -import { cRender, cRemove } from '../alien/Loader'; +import { Assertions, Keyboard, Keys } from '@ephox/agar'; +import { pRender, remove } from '../alien/Loader'; import { SugarElement } from '@ephox/sugar'; +import { Assert, describe, it } from '@ephox/bedrock-client'; -UnitTest.asynctest('InitTest', (success, failure) => { - const cFakeType = (str: string) => Chain.op((context: any) => { +describe('Editor Component Initialization Tests', () => { + // eslint-disable-next-line @typescript-eslint/require-await + const cFakeType = async (str: string, context: any) => { context.editor.getBody().innerHTML = '

' + str + '

'; Keyboard.keystroke(Keys.space(), {}, SugarElement.fromDom(context.editor.getBody()) as SugarElement); - }); + }; + + const testVersion = (version: '4' | '5' | '6' | '7') => { + describe(`Editor Initialization for Version ${version}`, () => { + it('should not be inline by default', async () => { + const context = await pRender(); + Assertions.assertEq('Editor should not be inline', false, context.editor.inline); + remove(); + }); - const sTestVersion = (version: '4' | '5' | '6' | '7') => VersionLoader.sWithVersion( - version, - GeneralSteps.sequence([ - Logger.t('Should be able to setup editor', Chain.asStep({}, [ - cRender(), - Chain.op((context) => { - Assertions.assertEq('Editor should not be inline', false, context.editor.inline); - }), - cRemove - ])), + it('should be inline with inline attribute in template', async () => { + const context = await pRender({}, ``); + Assertions.assertEq('Editor should be inline', true, context.editor.inline); + remove(); + }); - Logger.t('Should be able to setup editor', Chain.asStep({}, [ - cRender({}, ``), - Chain.op((context) => { - Assertions.assertEq('Editor should be inline', true, context.editor.inline); - }), - cRemove - ])), + it('should be inline with inline option in init', async () => { + const context = await pRender({ init: { inline: true }}); + Assertions.assertEq('Editor should be inline', true, context.editor.inline); + remove(); + }); - Logger.t('Should be able to setup editor', Chain.asStep({}, [ - cRender({ init: { inline: true }}), - Chain.op((context) => { - Assertions.assertEq('Editor should be inline', true, context.editor.inline); - }), - cRemove - ])), + it('should handle one-way binding with output-format="text"', async () => { + const context = await pRender({ + content: '' + }, ` + + `); + // Should we use type instead of cFakeType? + await cFakeType('A', context); + Assertions.assertEq('Content emitted should be of format="text"', 'A', context.vm.content); + remove(); + }); - Logger.t('Test one way binding tinymce-vue -> variable', GeneralSteps.sequence([ - Logger.t('Test outputFormat="text"', Chain.asStep({}, [ - cRender({ - content: undefined - }, ` - - `), - cFakeType('A'), - Chain.op((context) => { - Assertions.assertEq('Content emitted should be of format="text"', 'A', context.vm.content); - }), - cRemove - ])), - Logger.t('Test outputFormat="html"', Chain.asStep({}, [ - cRender({ - content: undefined - }, ` - - `), - cFakeType('A'), - Chain.op((context) => { - Assertions.assertEq('Content emitted should be of format="html"', '

A

', context.vm.content); - }), - cRemove - ])), - ])), - ]) - ); + it('should handle one-way binding with output-format="html"', async () => { + const context = await pRender({ + content: '' + }, ` + + `); + await cFakeType('A', context); + Assertions.assertEq('Content emitted should be of format="html"', '

A

', context.vm.content); + remove(); + }); + // Original test + // it('should handle one-way binding with output-format="text"', async () => { + // const context = await pRender({ + // content: '' + // }, ` + // + // `); + // await cFakeType('A', context); + // Assertions.assertEq('Content emitted should be of format="text"', 'A', context.vm.content); + // remove(); + // }); - Pipeline.async({}, [ - sTestVersion('4'), - sTestVersion('5'), - sTestVersion('6'), - sTestVersion('7'), - ], success, failure); -}); + // it('should handle one-way binding with output-format="html"', async () => { + // const context = await pRender({ + // content: '' + // }, ` + // + // `); + // await cFakeType('A', context); + // Assertions.assertEq('Content emitted should be of format="html"', '

A

', context.vm.content); + // remove(); + // }); + }); + }; + + Assert.succeeds('should test all versions', () => { + Promise.all([ + testVersion('4'), + testVersion('5'), + testVersion('6'), + testVersion('7'), + ]).then(() => { + // + }).catch((error) => { + // eslint-disable-next-line no-console + console.error('this is a error', error); + }); + }); +}); \ No newline at end of file diff --git a/src/test/ts/browser/LoadTinyTest.ts b/src/test/ts/browser/LoadTinyTest.ts index 8ef4aa0..6116bab 100644 --- a/src/test/ts/browser/LoadTinyTest.ts +++ b/src/test/ts/browser/LoadTinyTest.ts @@ -1,129 +1,151 @@ -import { Chain, Log, Pipeline, Assertions } from '@ephox/agar'; -import { UnitTest } from '@ephox/bedrock-client'; +import { Assertions } from '@ephox/agar'; +import { context, describe, it } from '@ephox/bedrock-client'; import { Arr, Strings, Global } from '@ephox/katamari'; import { SelectorFilter, Attribute, SugarElement, Remove } from '@ephox/sugar'; - -import { cRender, cRemove } from '../alien/Loader'; import { ScriptLoader } from '../../../main/ts/ScriptLoader'; +import { pRender } from '../alien/Loader'; -UnitTest.asynctest('LoadTinyTest', (success, failure) => { - const cDeleteTinymce = Chain.op(() => { +describe('LoadTinyTest', () => { + // Function to clean up and remove TinyMCE-related scripts and links from the document + const removeTinymce = () => { ScriptLoader.reinitialize(); + // Delete global references to TinyMCE, if they exist delete Global.tinymce; delete Global.tinyMCE; + // Helper function to check if an element has a TinyMCE-related URI in a specific attribute const hasTinymceUri = (attrName: string) => (elm: SugarElement) => Attribute.getOpt(elm, attrName).exists((src) => Strings.contains(src, 'tinymce')); + // Find all script and link elements that have a TinyMCE-related URI const elements = Arr.flatten([ Arr.filter(SelectorFilter.all('script'), hasTinymceUri('src')), Arr.filter(SelectorFilter.all('link'), hasTinymceUri('href')), ]); Arr.each(elements, Remove.remove); - }); + }; - const cAssertTinymceVersion = (version: '4' | '5' | '6' | '7') => Chain.op(() => { + const AssertTinymceVersion = (version: '4' | '5' | '6' | '7') => { Assertions.assertEq(`Loaded version of TinyMCE should be ${version}`, version, Global.tinymce.majorVersion); - }); + }; - Pipeline.async({}, [ - Log.chainsAsStep('Should be able to load local version of TinyMCE using the tinymceScriptSrc prop', '', [ - cDeleteTinymce, + context('LoadTinyTest', () => { + it('Should be able to load local version of TinyMCE using the tinymceScriptSrc prop', async () => { + removeTinymce(); - cRender({}, ` + await pRender({}, ` - `), - cAssertTinymceVersion('7'), - cRemove, - cDeleteTinymce, + `); - cRender({}, ` - - `), - cAssertTinymceVersion('6'), - cRemove, - cDeleteTinymce, + AssertTinymceVersion('7'); + removeTinymce(); + }); + }); +}); - cRender({}, ` - - `), - cAssertTinymceVersion('5'), - cRemove, - cDeleteTinymce, - cRender({}, ` - - `), - cAssertTinymceVersion('4'), - cRemove, - cDeleteTinymce, - ]), - Log.chainsAsStep('Should be able to load TinyMCE from Cloud', '', [ - cRender({}, ` - - `), - cAssertTinymceVersion('7'), - Chain.op(() => { - Assertions.assertEq( - 'TinyMCE should have been loaded from Cloud', - 'https://cdn.tiny.cloud/1/a-fake-api-key/tinymce/7-stable', - Global.tinymce.baseURI.source - ); - }), - cRemove, - cDeleteTinymce, - cRender({}, ` - - `), - cAssertTinymceVersion('6'), - Chain.op(() => { - Assertions.assertEq( - 'TinyMCE should have been loaded from Cloud', - 'https://cdn.tiny.cloud/1/a-fake-api-key/tinymce/6-stable', - Global.tinymce.baseURI.source - ); - }), - cRemove, - cDeleteTinymce, - cRender({}, ` - - `), - cAssertTinymceVersion('5'), - Chain.op(() => { - Assertions.assertEq( - 'TinyMCE should have been loaded from Cloud', - 'https://cdn.tiny.cloud/1/a-fake-api-key/tinymce/5-stable', - Global.tinymce.baseURI.source - ); - }), - cRemove, - cDeleteTinymce - ]), - ], success, failure); -}); + + // TODO: Add the below tests for loading TinyMCE from Cloud + // Pipeline.async({}, [ + // Log.chainsAsStep('Should be able to load local version of TinyMCE using the tinymceScriptSrc prop', '', [ + // cDeleteTinymce, + + // cRender({}, ` + // + // `), + // cAssertTinymceVersion('7'), + // cRemove, + // cDeleteTinymce, + + // cRender({}, ` + // + // `), + // cAssertTinymceVersion('6'), + // cRemove, + // cDeleteTinymce, + + // cRender({}, ` + // + // `), + // cAssertTinymceVersion('5'), + // cRemove, + // cDeleteTinymce, + + // cRender({}, ` + // + // `), + // cAssertTinymceVersion('4'), + // cRemove, + // cDeleteTinymce, + // ]), + // Log.chainsAsStep('Should be able to load TinyMCE from Cloud', '', [ + // cRender({}, ` + // + // `), + // cAssertTinymceVersion('7'), + // Chain.op(() => { + // Assertions.assertEq( + // 'TinyMCE should have been loaded from Cloud', + // 'https://cdn.tiny.cloud/1/a-fake-api-key/tinymce/7-stable', + // Global.tinymce.baseURI.source + // ); + // }), + // cRemove, + // cDeleteTinymce, + // cRender({}, ` + // + // `), + // cAssertTinymceVersion('6'), + // Chain.op(() => { + // Assertions.assertEq( + // 'TinyMCE should have been loaded from Cloud', + // 'https://cdn.tiny.cloud/1/a-fake-api-key/tinymce/6-stable', + // Global.tinymce.baseURI.source + // ); + // }), + // cRemove, + // cDeleteTinymce, + // cRender({}, ` + // + // `), + // cAssertTinymceVersion('5'), + // Chain.op(() => { + // Assertions.assertEq( + // 'TinyMCE should have been loaded from Cloud', + // 'https://cdn.tiny.cloud/1/a-fake-api-key/tinymce/5-stable', + // Global.tinymce.baseURI.source + // ); + // }), + // cRemove, + // cDeleteTinymce, + // ]), + // ], success, failure); From 10c68a4cbaafcd69a38cf134cfcfe62768eab49d Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Mon, 9 Sep 2024 09:20:08 +1000 Subject: [PATCH 02/17] create TestHelper.ts to isolate variables update imports --- src/test/ts/alien/Loader.ts | 6 +-- src/test/ts/alien/TestHelper.ts | 31 ++++++++++++++ src/test/ts/browser/InitTest.ts | 65 +++++++++-------------------- src/test/ts/browser/LoadTinyTest.ts | 29 ++----------- 4 files changed, 56 insertions(+), 75 deletions(-) create mode 100644 src/test/ts/alien/TestHelper.ts diff --git a/src/test/ts/alien/Loader.ts b/src/test/ts/alien/Loader.ts index 7d9faf8..111fac7 100644 --- a/src/test/ts/alien/Loader.ts +++ b/src/test/ts/alien/Loader.ts @@ -18,7 +18,7 @@ const getRoot = () => SelectorFind.descendant(SugarBody.body(), '#root').getOrTh return root; }); -const pRender = (data: Record = {}, template: string = ``): Promise => new Promise((resolve) => { +const pRender = (data: Record = {}, template: string = ``): Promise => new Promise((resolve) => { const root = getRoot(); const mountPoint = SugarElement.fromTag('div'); Insert.append(root, mountPoint); @@ -36,9 +36,7 @@ const pRender = (data: Record = {}, template: string = ` { + setup: (editor: any) => { originalSetup(editor); editor.on('SkinLoaded', () => { setTimeout(() => { diff --git a/src/test/ts/alien/TestHelper.ts b/src/test/ts/alien/TestHelper.ts new file mode 100644 index 0000000..3e4afe7 --- /dev/null +++ b/src/test/ts/alien/TestHelper.ts @@ -0,0 +1,31 @@ +import { Global, Strings, Arr } from '@ephox/katamari'; +import { SugarElement, Attribute, SelectorFilter, Remove } from '@ephox/sugar'; +import { ScriptLoader } from '../../../main/ts/ScriptLoader'; + +const VALID_API_KEY = 'qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc'; + +// Function to clean up and remove TinyMCE-related scripts and links from the document +const cleanupTinymce = () => { + ScriptLoader.reinitialize(); + + // Delete global references to TinyMCE, if they exist + delete Global.tinymce; + delete Global.tinyMCE; + + // Helper function to check if an element has a TinyMCE-related URI in a specific attribute + const hasTinymceUri = (attrName: string) => (elm: SugarElement) => + Attribute.getOpt(elm, attrName).exists((src) => Strings.contains(src, 'tinymce')); + + // Find all script and link elements that have a TinyMCE-related URI + const elements = Arr.flatten([ + Arr.filter(SelectorFilter.all('script'), hasTinymceUri('src')), + Arr.filter(SelectorFilter.all('link'), hasTinymceUri('href')), + ]); + + Arr.each(elements, Remove.remove); +}; + +export { + VALID_API_KEY, + cleanupTinymce, +}; \ No newline at end of file diff --git a/src/test/ts/browser/InitTest.ts b/src/test/ts/browser/InitTest.ts index 041d352..8cd4253 100644 --- a/src/test/ts/browser/InitTest.ts +++ b/src/test/ts/browser/InitTest.ts @@ -1,7 +1,8 @@ import { Assertions, Keyboard, Keys } from '@ephox/agar'; -import { pRender, remove } from '../alien/Loader'; +import { pRender } from '../alien/Loader'; import { SugarElement } from '@ephox/sugar'; import { Assert, describe, it } from '@ephox/bedrock-client'; +import { cleanupTinymce, VALID_API_KEY } from '../alien/TestHelper'; describe('Editor Component Initialization Tests', () => { // eslint-disable-next-line @typescript-eslint/require-await @@ -15,81 +16,55 @@ describe('Editor Component Initialization Tests', () => { it('should not be inline by default', async () => { const context = await pRender(); Assertions.assertEq('Editor should not be inline', false, context.editor.inline); - remove(); + cleanupTinymce(); }); it('should be inline with inline attribute in template', async () => { - const context = await pRender({}, ``); + const context = await pRender({}, ` + `); Assertions.assertEq('Editor should be inline', true, context.editor.inline); - remove(); + cleanupTinymce(); }); it('should be inline with inline option in init', async () => { const context = await pRender({ init: { inline: true }}); Assertions.assertEq('Editor should be inline', true, context.editor.inline); - remove(); + cleanupTinymce(); }); - it('should handle one-way binding with output-format="text"', async () => { const context = await pRender({ - content: '' + content: undefined, }, ` `); - // Should we use type instead of cFakeType? - await cFakeType('A', context); + cFakeType('A', context); Assertions.assertEq('Content emitted should be of format="text"', 'A', context.vm.content); - remove(); + cleanupTinymce(); }); it('should handle one-way binding with output-format="html"', async () => { const context = await pRender({ - content: '' + content: undefined, }, ` `); await cFakeType('A', context); - Assertions.assertEq('Content emitted should be of format="html"', '

A

', context.vm.content); - remove(); + Assertions.assertEq('Content emitted should be of format="html"', '

A

', context.editor.content); + cleanupTinymce(); }); - // Original test - // it('should handle one-way binding with output-format="text"', async () => { - // const context = await pRender({ - // content: '' - // }, ` - // - // `); - // await cFakeType('A', context); - // Assertions.assertEq('Content emitted should be of format="text"', 'A', context.vm.content); - // remove(); - // }); - - // it('should handle one-way binding with output-format="html"', async () => { - // const context = await pRender({ - // content: '' - // }, ` - // - // `); - // await cFakeType('A', context); - // Assertions.assertEq('Content emitted should be of format="html"', '

A

', context.vm.content); - // remove(); - // }); }); }; diff --git a/src/test/ts/browser/LoadTinyTest.ts b/src/test/ts/browser/LoadTinyTest.ts index 6116bab..5993b3a 100644 --- a/src/test/ts/browser/LoadTinyTest.ts +++ b/src/test/ts/browser/LoadTinyTest.ts @@ -1,31 +1,10 @@ import { Assertions } from '@ephox/agar'; import { context, describe, it } from '@ephox/bedrock-client'; -import { Arr, Strings, Global } from '@ephox/katamari'; -import { SelectorFilter, Attribute, SugarElement, Remove } from '@ephox/sugar'; -import { ScriptLoader } from '../../../main/ts/ScriptLoader'; +import { Global } from '@ephox/katamari'; import { pRender } from '../alien/Loader'; +import { cleanupTinymce } from '../alien/TestHelper'; describe('LoadTinyTest', () => { - // Function to clean up and remove TinyMCE-related scripts and links from the document - const removeTinymce = () => { - ScriptLoader.reinitialize(); - - // Delete global references to TinyMCE, if they exist - delete Global.tinymce; - delete Global.tinyMCE; - - // Helper function to check if an element has a TinyMCE-related URI in a specific attribute - const hasTinymceUri = (attrName: string) => (elm: SugarElement) => - Attribute.getOpt(elm, attrName).exists((src) => Strings.contains(src, 'tinymce')); - - // Find all script and link elements that have a TinyMCE-related URI - const elements = Arr.flatten([ - Arr.filter(SelectorFilter.all('script'), hasTinymceUri('src')), - Arr.filter(SelectorFilter.all('link'), hasTinymceUri('href')), - ]); - - Arr.each(elements, Remove.remove); - }; const AssertTinymceVersion = (version: '4' | '5' | '6' | '7') => { Assertions.assertEq(`Loaded version of TinyMCE should be ${version}`, version, Global.tinymce.majorVersion); @@ -33,8 +12,6 @@ describe('LoadTinyTest', () => { context('LoadTinyTest', () => { it('Should be able to load local version of TinyMCE using the tinymceScriptSrc prop', async () => { - removeTinymce(); - await pRender({}, ` { `); AssertTinymceVersion('7'); - removeTinymce(); + cleanupTinymce(); }); }); }); From bb56803bba16b86661cb93916559f75580420050 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Mon, 9 Sep 2024 11:10:34 +1000 Subject: [PATCH 03/17] remove async from cFakeType function. --- src/test/ts/browser/InitTest.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/ts/browser/InitTest.ts b/src/test/ts/browser/InitTest.ts index 8cd4253..b476801 100644 --- a/src/test/ts/browser/InitTest.ts +++ b/src/test/ts/browser/InitTest.ts @@ -6,7 +6,7 @@ import { cleanupTinymce, VALID_API_KEY } from '../alien/TestHelper'; describe('Editor Component Initialization Tests', () => { // eslint-disable-next-line @typescript-eslint/require-await - const cFakeType = async (str: string, context: any) => { + const cFakeType = (str: string, context: any) => { context.editor.getBody().innerHTML = '

' + str + '

'; Keyboard.keystroke(Keys.space(), {}, SugarElement.fromDom(context.editor.getBody()) as SugarElement); }; @@ -61,8 +61,8 @@ describe('Editor Component Initialization Tests', () => { output-format="html" >
`); - await cFakeType('A', context); - Assertions.assertEq('Content emitted should be of format="html"', '

A

', context.editor.content); + cFakeType('A', context); + Assertions.assertEq('Content emitted should be of format="html"', '

A

', context.vm.content); cleanupTinymce(); }); }); From a5a9a6dcfb462812ea6dd50a037064451f8f8425 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Mon, 9 Sep 2024 11:53:19 +1000 Subject: [PATCH 04/17] Add test to LoadTinyTest.ts for loading from scriptSrc and Cloud. --- src/test/ts/alien/TestHelper.ts | 4 - src/test/ts/atomic/UtilsTest.ts | 1 - src/test/ts/browser/LoadTinyTest.ts | 185 ++++++++++++---------------- 3 files changed, 82 insertions(+), 108 deletions(-) diff --git a/src/test/ts/alien/TestHelper.ts b/src/test/ts/alien/TestHelper.ts index 3e4afe7..e529fbc 100644 --- a/src/test/ts/alien/TestHelper.ts +++ b/src/test/ts/alien/TestHelper.ts @@ -7,21 +7,17 @@ const VALID_API_KEY = 'qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc'; // Function to clean up and remove TinyMCE-related scripts and links from the document const cleanupTinymce = () => { ScriptLoader.reinitialize(); - // Delete global references to TinyMCE, if they exist delete Global.tinymce; delete Global.tinyMCE; - // Helper function to check if an element has a TinyMCE-related URI in a specific attribute const hasTinymceUri = (attrName: string) => (elm: SugarElement) => Attribute.getOpt(elm, attrName).exists((src) => Strings.contains(src, 'tinymce')); - // Find all script and link elements that have a TinyMCE-related URI const elements = Arr.flatten([ Arr.filter(SelectorFilter.all('script'), hasTinymceUri('src')), Arr.filter(SelectorFilter.all('link'), hasTinymceUri('href')), ]); - Arr.each(elements, Remove.remove); }; diff --git a/src/test/ts/atomic/UtilsTest.ts b/src/test/ts/atomic/UtilsTest.ts index 067bca3..46bae4e 100644 --- a/src/test/ts/atomic/UtilsTest.ts +++ b/src/test/ts/atomic/UtilsTest.ts @@ -7,7 +7,6 @@ describe('UtilsTest', () => { const actual = isValidKey(key); Assertions.assertEq('Key is valid', expected, actual); }; - it('should check if key is valid onKeyUp', () => { checkValidKey('onKeyUp', true); }); diff --git a/src/test/ts/browser/LoadTinyTest.ts b/src/test/ts/browser/LoadTinyTest.ts index 5993b3a..561b451 100644 --- a/src/test/ts/browser/LoadTinyTest.ts +++ b/src/test/ts/browser/LoadTinyTest.ts @@ -2,7 +2,7 @@ import { Assertions } from '@ephox/agar'; import { context, describe, it } from '@ephox/bedrock-client'; import { Global } from '@ephox/katamari'; import { pRender } from '../alien/Loader'; -import { cleanupTinymce } from '../alien/TestHelper'; +import { cleanupTinymce, VALID_API_KEY } from '../alien/TestHelper'; describe('LoadTinyTest', () => { @@ -11,7 +11,7 @@ describe('LoadTinyTest', () => { }; context('LoadTinyTest', () => { - it('Should be able to load local version of TinyMCE using the tinymceScriptSrc prop', async () => { + it('Should be able to load local version of TinyMCE 7 using the tinymceScriptSrc prop', async () => { await pRender({}, ` { AssertTinymceVersion('7'); cleanupTinymce(); }); - }); -}); - - - - // TODO: Add the below tests for loading TinyMCE from Cloud - // Pipeline.async({}, [ - // Log.chainsAsStep('Should be able to load local version of TinyMCE using the tinymceScriptSrc prop', '', [ - // cDeleteTinymce, - - // cRender({}, ` - // - // `), - // cAssertTinymceVersion('7'), - // cRemove, - // cDeleteTinymce, + it('Should be able to load local version of TinyMCE 6 using the tinymceScriptSrc prop', async () => { + await pRender({}, ` + + `); - // cRender({}, ` - // - // `), - // cAssertTinymceVersion('6'), - // cRemove, - // cDeleteTinymce, + AssertTinymceVersion('6'); + cleanupTinymce(); + }); + it('Should be able to load local version of TinyMCE 5 using the tinymceScriptSrc prop', async () => { + await pRender({}, ` + + `); - // cRender({}, ` - // - // `), - // cAssertTinymceVersion('5'), - // cRemove, - // cDeleteTinymce, + AssertTinymceVersion('5'); + cleanupTinymce(); + }); + it('Should be able to load local version of TinyMCE 4 using the tinymceScriptSrc prop', async () => { + await pRender({}, ` + + `); - // cRender({}, ` - // - // `), - // cAssertTinymceVersion('4'), - // cRemove, - // cDeleteTinymce, - // ]), - // Log.chainsAsStep('Should be able to load TinyMCE from Cloud', '', [ - // cRender({}, ` - // - // `), - // cAssertTinymceVersion('7'), - // Chain.op(() => { - // Assertions.assertEq( - // 'TinyMCE should have been loaded from Cloud', - // 'https://cdn.tiny.cloud/1/a-fake-api-key/tinymce/7-stable', - // Global.tinymce.baseURI.source - // ); - // }), - // cRemove, - // cDeleteTinymce, - // cRender({}, ` - // - // `), - // cAssertTinymceVersion('6'), - // Chain.op(() => { - // Assertions.assertEq( - // 'TinyMCE should have been loaded from Cloud', - // 'https://cdn.tiny.cloud/1/a-fake-api-key/tinymce/6-stable', - // Global.tinymce.baseURI.source - // ); - // }), - // cRemove, - // cDeleteTinymce, - // cRender({}, ` - // - // `), - // cAssertTinymceVersion('5'), - // Chain.op(() => { - // Assertions.assertEq( - // 'TinyMCE should have been loaded from Cloud', - // 'https://cdn.tiny.cloud/1/a-fake-api-key/tinymce/5-stable', - // Global.tinymce.baseURI.source - // ); - // }), - // cRemove, - // cDeleteTinymce, - // ]), - // ], success, failure); + AssertTinymceVersion('4'); + cleanupTinymce(); + }); + it('Should be able to load TinyMCE 7 from Cloud', async () => { + await pRender({}, ` + + `); + AssertTinymceVersion('7'); + Assertions.assertEq( + 'TinyMCE 7 should have been loaded from Cloud', + `https://cdn.tiny.cloud/1/${VALID_API_KEY}/tinymce/7-stable`, + Global.tinymce.baseURI.source + ); + cleanupTinymce(); + }); + it('Should be able to load TinyMCE 6 from Cloud', async () => { + await pRender({}, ` + + `); + AssertTinymceVersion('6'); + Assertions.assertEq( + 'TinyMCE 6 should have been loaded from Cloud', + `https://cdn.tiny.cloud/1/${VALID_API_KEY}/tinymce/6-stable`, + Global.tinymce.baseURI.source + ); + cleanupTinymce(); + }); + it('Should be able to load TinyMCE 5 from Cloud', async () => { + await pRender({}, ` + + `); + AssertTinymceVersion('5'); + Assertions.assertEq( + 'TinyMCE 5 should have been loaded from Cloud', + `https://cdn.tiny.cloud/1/${VALID_API_KEY}/tinymce/5-stable`, + Global.tinymce.baseURI.source + ); + cleanupTinymce(); + }); + }); +}); \ No newline at end of file From 38ba52b5fd522709ef4986ecaf7327af7f21a161 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Wed, 11 Sep 2024 15:19:23 +1000 Subject: [PATCH 05/17] INT-3303: Convert cFakeType to asynchronous. --- src/test/ts/browser/InitTest.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/ts/browser/InitTest.ts b/src/test/ts/browser/InitTest.ts index b476801..821782c 100644 --- a/src/test/ts/browser/InitTest.ts +++ b/src/test/ts/browser/InitTest.ts @@ -6,7 +6,7 @@ import { cleanupTinymce, VALID_API_KEY } from '../alien/TestHelper'; describe('Editor Component Initialization Tests', () => { // eslint-disable-next-line @typescript-eslint/require-await - const cFakeType = (str: string, context: any) => { + const pFakeType = async (str: string, context: any) => { context.editor.getBody().innerHTML = '

' + str + '

'; Keyboard.keystroke(Keys.space(), {}, SugarElement.fromDom(context.editor.getBody()) as SugarElement); }; @@ -45,7 +45,7 @@ describe('Editor Component Initialization Tests', () => { output-format="text" >
`); - cFakeType('A', context); + await pFakeType('A', context); Assertions.assertEq('Content emitted should be of format="text"', 'A', context.vm.content); cleanupTinymce(); }); @@ -61,7 +61,7 @@ describe('Editor Component Initialization Tests', () => { output-format="html" >
`); - cFakeType('A', context); + await pFakeType('A', context); Assertions.assertEq('Content emitted should be of format="html"', '

A

', context.vm.content); cleanupTinymce(); }); From 105e1faf491979c53cf292cd8ad16ba1e9e8250b Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Wed, 11 Sep 2024 16:02:13 +1000 Subject: [PATCH 06/17] INT-3303: Refactor InitTest.ts and related files. --- src/test/ts/browser/InitTest.ts | 128 ++++++++++++++------------------ 1 file changed, 56 insertions(+), 72 deletions(-) diff --git a/src/test/ts/browser/InitTest.ts b/src/test/ts/browser/InitTest.ts index 821782c..5615c38 100644 --- a/src/test/ts/browser/InitTest.ts +++ b/src/test/ts/browser/InitTest.ts @@ -1,84 +1,68 @@ -import { Assertions, Keyboard, Keys } from '@ephox/agar'; +import { Assertions, Keyboard, Keys, Waiter } from '@ephox/agar'; import { pRender } from '../alien/Loader'; import { SugarElement } from '@ephox/sugar'; -import { Assert, describe, it } from '@ephox/bedrock-client'; +import { describe, it, afterEach } from '@ephox/bedrock-client'; import { cleanupTinymce, VALID_API_KEY } from '../alien/TestHelper'; describe('Editor Component Initialization Tests', () => { // eslint-disable-next-line @typescript-eslint/require-await - const pFakeType = async (str: string, context: any) => { - context.editor.getBody().innerHTML = '

' + str + '

'; - Keyboard.keystroke(Keys.space(), {}, SugarElement.fromDom(context.editor.getBody()) as SugarElement); + const pFakeType = async (str: string, vmContext: any) => { + vmContext.editor.getBody().innerHTML = '

' + str + '

'; + Keyboard.keystroke(Keys.space(), {}, SugarElement.fromDom(vmContext.editor.getBody()) as SugarElement); }; + afterEach(() => { + cleanupTinymce(); + }); + it('should not be inline by default', async () => { + const vmContext = await pRender({}, ` + `); + Assertions.assertEq('Editor should not be inline', false, vmContext.editor.inline); + }); - const testVersion = (version: '4' | '5' | '6' | '7') => { - describe(`Editor Initialization for Version ${version}`, () => { - it('should not be inline by default', async () => { - const context = await pRender(); - Assertions.assertEq('Editor should not be inline', false, context.editor.inline); - cleanupTinymce(); - }); - - it('should be inline with inline attribute in template', async () => { - const context = await pRender({}, ` - `); - Assertions.assertEq('Editor should be inline', true, context.editor.inline); - cleanupTinymce(); - }); - - it('should be inline with inline option in init', async () => { - const context = await pRender({ init: { inline: true }}); - Assertions.assertEq('Editor should be inline', true, context.editor.inline); - cleanupTinymce(); - }); - it('should handle one-way binding with output-format="text"', async () => { - const context = await pRender({ - content: undefined, - }, ` - - `); - await pFakeType('A', context); - Assertions.assertEq('Content emitted should be of format="text"', 'A', context.vm.content); - cleanupTinymce(); - }); + it('should be inline with inline attribute in template', async () => { + const vmContext = await pRender({}, ` + `); + Assertions.assertEq('Editor should be inline', true, vmContext.editor.inline); + }); - it('should handle one-way binding with output-format="html"', async () => { - const context = await pRender({ - content: undefined, - }, ` - - `); - await pFakeType('A', context); - Assertions.assertEq('Content emitted should be of format="html"', '

A

', context.vm.content); - cleanupTinymce(); - }); - }); - }; + it('should be inline with inline option in init', async () => { + const vmContext = await pRender({ init: { inline: true }}); + Assertions.assertEq('Editor should be inline', true, vmContext.editor.inline); + }); + it('should handle one-way binding with output-format="text"', async () => { + const vmContext = await pRender({ + content: undefined, + }, ` + + `); + await pFakeType('A', vmContext); + await Waiter.pWait(100); + Assertions.assertEq('Content emitted should be of format="text"', 'A', vmContext.vm.content); + }); - Assert.succeeds('should test all versions', () => { - Promise.all([ - testVersion('4'), - testVersion('5'), - testVersion('6'), - testVersion('7'), - ]).then(() => { - // - }).catch((error) => { - // eslint-disable-next-line no-console - console.error('this is a error', error); - }); + it('should handle one-way binding with output-format="html"', async () => { + const vmContext = await pRender({ + content: undefined, + }, ` + + `); + await pFakeType('A', vmContext); + await Waiter.pWait(100); + Assertions.assertEq('Content emitted should be of format="html"', '

A

', vmContext.vm.content); }); }); \ No newline at end of file From 6d1df84dec54b1fd1de77d4bd33a75bcad5e23c6 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Fri, 13 Sep 2024 08:51:00 +1000 Subject: [PATCH 07/17] add loop to iterate each editor version for tests. --- src/test/ts/browser/InitTest.ts | 113 ++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 50 deletions(-) diff --git a/src/test/ts/browser/InitTest.ts b/src/test/ts/browser/InitTest.ts index 5615c38..f2ee21e 100644 --- a/src/test/ts/browser/InitTest.ts +++ b/src/test/ts/browser/InitTest.ts @@ -1,8 +1,10 @@ import { Assertions, Keyboard, Keys, Waiter } from '@ephox/agar'; import { pRender } from '../alien/Loader'; +import { VersionLoader } from '@tinymce/miniature'; // Add this line import { SugarElement } from '@ephox/sugar'; -import { describe, it, afterEach } from '@ephox/bedrock-client'; +import { describe, it, afterEach, before, context } from '@ephox/bedrock-client'; import { cleanupTinymce, VALID_API_KEY } from '../alien/TestHelper'; +import { Arr } from '@ephox/katamari'; describe('Editor Component Initialization Tests', () => { // eslint-disable-next-line @typescript-eslint/require-await @@ -10,59 +12,70 @@ describe('Editor Component Initialization Tests', () => { vmContext.editor.getBody().innerHTML = '

' + str + '

'; Keyboard.keystroke(Keys.space(), {}, SugarElement.fromDom(vmContext.editor.getBody()) as SugarElement); }; + afterEach(() => { cleanupTinymce(); }); - it('should not be inline by default', async () => { - const vmContext = await pRender({}, ` - `); - Assertions.assertEq('Editor should not be inline', false, vmContext.editor.inline); - }); - it('should be inline with inline attribute in template', async () => { - const vmContext = await pRender({}, ` - `); - Assertions.assertEq('Editor should be inline', true, vmContext.editor.inline); - }); + Arr.each([ '4', '5', '6', '7' as const ], (version) => { + context(`Version: ${version}`, () => { + before(async () => { + await VersionLoader.pLoadVersion(version); + }); - it('should be inline with inline option in init', async () => { - const vmContext = await pRender({ init: { inline: true }}); - Assertions.assertEq('Editor should be inline', true, vmContext.editor.inline); - }); - it('should handle one-way binding with output-format="text"', async () => { - const vmContext = await pRender({ - content: undefined, - }, ` - - `); - await pFakeType('A', vmContext); - await Waiter.pWait(100); - Assertions.assertEq('Content emitted should be of format="text"', 'A', vmContext.vm.content); - }); + it('should not be inline by default', async () => { + const vmContext = await pRender({}, ` + `); + Assertions.assertEq('Editor should not be inline', false, vmContext.editor.inline); + }); + + it('should be inline with inline attribute in template', async () => { + const vmContext = await pRender({}, ` + `); + Assertions.assertEq('Editor should be inline', true, vmContext.editor.inline); + }); + + it('should be inline with inline option in init', async () => { + const vmContext = await pRender({ init: { inline: true }}); + Assertions.assertEq('Editor should be inline', true, vmContext.editor.inline); + }); + + it('should handle one-way binding with output-format="text"', async () => { + const vmContext = await pRender({ + content: undefined, + }, ` + + `); + await pFakeType('A', vmContext); + await Waiter.pWait(100); + Assertions.assertEq('Content emitted should be of format="text"', 'A', vmContext.vm.content); + }); - it('should handle one-way binding with output-format="html"', async () => { - const vmContext = await pRender({ - content: undefined, - }, ` - - `); - await pFakeType('A', vmContext); - await Waiter.pWait(100); - Assertions.assertEq('Content emitted should be of format="html"', '

A

', vmContext.vm.content); + it('should handle one-way binding with output-format="html"', async () => { + const vmContext = await pRender({ + content: undefined, + }, ` + + `); + await pFakeType('A', vmContext); + await Waiter.pWait(100); + Assertions.assertEq('Content emitted should be of format="html"', '

A

', vmContext.vm.content); + }); + }); }); -}); \ No newline at end of file +}); From e71bef9e2de555e97bf09ef0ed7e9b3228b326e0 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Fri, 13 Sep 2024 09:00:06 +1000 Subject: [PATCH 08/17] afterEach function was added inside the loop for different versions. --- src/test/ts/browser/InitTest.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/test/ts/browser/InitTest.ts b/src/test/ts/browser/InitTest.ts index f2ee21e..de8cfca 100644 --- a/src/test/ts/browser/InitTest.ts +++ b/src/test/ts/browser/InitTest.ts @@ -13,12 +13,11 @@ describe('Editor Component Initialization Tests', () => { Keyboard.keystroke(Keys.space(), {}, SugarElement.fromDom(vmContext.editor.getBody()) as SugarElement); }; - afterEach(() => { - cleanupTinymce(); - }); - Arr.each([ '4', '5', '6', '7' as const ], (version) => { context(`Version: ${version}`, () => { + afterEach(() => { + cleanupTinymce(); + }); before(async () => { await VersionLoader.pLoadVersion(version); }); From b9ff917fa5a865a0805bf276f674184a896c9556 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Fri, 13 Sep 2024 11:59:06 +1000 Subject: [PATCH 09/17] INT-3303: Fix defaultValue warning. update cleanupTinymce to cleanupGlobalTinymce to be more specific. fix spacing between tests. add afterEach to context function. --- src/stories/Editor.stories.tsx | 3 ++- src/test/ts/alien/TestHelper.ts | 4 ++-- src/test/ts/atomic/UtilsTest.ts | 3 +++ src/test/ts/browser/InitTest.ts | 18 ++++++++++++------ src/test/ts/browser/LoadTinyTest.ts | 22 ++++++++++++++-------- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/stories/Editor.stories.tsx b/src/stories/Editor.stories.tsx index 8c0ab12..93d69f9 100644 --- a/src/stories/Editor.stories.tsx +++ b/src/stories/Editor.stories.tsx @@ -52,7 +52,7 @@ export default { table: { defaultValue: {summary: '5'} }, - defaultValue: ['7'], + defaultValue: '7', options: ['5', '5-dev', '5-testing', '6-testing', '6-stable', '7-dev', '7-testing', '7-stable'], control: { type: 'select'} }, @@ -80,6 +80,7 @@ export const Iframe: Story = (args) => ({ const cc = args.channel || lastChannel; const conf = getConf(args.conf); console.log('conf: ', conf); + console.log('channel: ', cc); return { apiKey, content, diff --git a/src/test/ts/alien/TestHelper.ts b/src/test/ts/alien/TestHelper.ts index e529fbc..e1e38d8 100644 --- a/src/test/ts/alien/TestHelper.ts +++ b/src/test/ts/alien/TestHelper.ts @@ -5,7 +5,7 @@ import { ScriptLoader } from '../../../main/ts/ScriptLoader'; const VALID_API_KEY = 'qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc'; // Function to clean up and remove TinyMCE-related scripts and links from the document -const cleanupTinymce = () => { +const cleanupGlobalTinymce = () => { ScriptLoader.reinitialize(); // Delete global references to TinyMCE, if they exist delete Global.tinymce; @@ -23,5 +23,5 @@ const cleanupTinymce = () => { export { VALID_API_KEY, - cleanupTinymce, + cleanupGlobalTinymce, }; \ No newline at end of file diff --git a/src/test/ts/atomic/UtilsTest.ts b/src/test/ts/atomic/UtilsTest.ts index 46bae4e..1de85c2 100644 --- a/src/test/ts/atomic/UtilsTest.ts +++ b/src/test/ts/atomic/UtilsTest.ts @@ -7,12 +7,15 @@ describe('UtilsTest', () => { const actual = isValidKey(key); Assertions.assertEq('Key is valid', expected, actual); }; + it('should check if key is valid onKeyUp', () => { checkValidKey('onKeyUp', true); }); + it('should check if key is valid onkeyup', () => { checkValidKey('onkeyup', true); }); + it('should check if key is valid onDisable', () => { checkValidKey('onDisable', false); }); diff --git a/src/test/ts/browser/InitTest.ts b/src/test/ts/browser/InitTest.ts index de8cfca..b1e16a9 100644 --- a/src/test/ts/browser/InitTest.ts +++ b/src/test/ts/browser/InitTest.ts @@ -1,9 +1,9 @@ import { Assertions, Keyboard, Keys, Waiter } from '@ephox/agar'; -import { pRender } from '../alien/Loader'; +import { pRender, remove } from '../alien/Loader'; import { VersionLoader } from '@tinymce/miniature'; // Add this line import { SugarElement } from '@ephox/sugar'; -import { describe, it, afterEach, before, context } from '@ephox/bedrock-client'; -import { cleanupTinymce, VALID_API_KEY } from '../alien/TestHelper'; +import { describe, it, afterEach, before, context, after } from '@ephox/bedrock-client'; +import { cleanupGlobalTinymce, VALID_API_KEY } from '../alien/TestHelper'; import { Arr } from '@ephox/katamari'; describe('Editor Component Initialization Tests', () => { @@ -15,13 +15,19 @@ describe('Editor Component Initialization Tests', () => { Arr.each([ '4', '5', '6', '7' as const ], (version) => { context(`Version: ${version}`, () => { - afterEach(() => { - cleanupTinymce(); - }); + before(async () => { await VersionLoader.pLoadVersion(version); }); + after(() => { + cleanupGlobalTinymce(); + }); + + afterEach(() => { + remove(); + }); + it('should not be inline by default', async () => { const vmContext = await pRender({}, ` { @@ -20,8 +20,9 @@ describe('LoadTinyTest', () => { `); AssertTinymceVersion('7'); - cleanupTinymce(); + cleanupGlobalTinymce(); }); + it('Should be able to load local version of TinyMCE 6 using the tinymceScriptSrc prop', async () => { await pRender({}, ` { `); AssertTinymceVersion('6'); - cleanupTinymce(); + cleanupGlobalTinymce(); }); + it('Should be able to load local version of TinyMCE 5 using the tinymceScriptSrc prop', async () => { await pRender({}, ` { `); AssertTinymceVersion('5'); - cleanupTinymce(); + cleanupGlobalTinymce(); }); + it('Should be able to load local version of TinyMCE 4 using the tinymceScriptSrc prop', async () => { await pRender({}, ` { `); AssertTinymceVersion('4'); - cleanupTinymce(); + cleanupGlobalTinymce(); }); + it('Should be able to load TinyMCE 7 from Cloud', async () => { await pRender({}, ` { `https://cdn.tiny.cloud/1/${VALID_API_KEY}/tinymce/7-stable`, Global.tinymce.baseURI.source ); - cleanupTinymce(); + cleanupGlobalTinymce(); }); + it('Should be able to load TinyMCE 6 from Cloud', async () => { await pRender({}, ` { `https://cdn.tiny.cloud/1/${VALID_API_KEY}/tinymce/6-stable`, Global.tinymce.baseURI.source ); - cleanupTinymce(); + cleanupGlobalTinymce(); }); + it('Should be able to load TinyMCE 5 from Cloud', async () => { await pRender({}, ` { `https://cdn.tiny.cloud/1/${VALID_API_KEY}/tinymce/5-stable`, Global.tinymce.baseURI.source ); - cleanupTinymce(); + cleanupGlobalTinymce(); }); }); }); \ No newline at end of file From 3d7929201717a67b64fa27c4ca3f29cfb85846d3 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Fri, 13 Sep 2024 13:22:48 +1000 Subject: [PATCH 10/17] INT-3303: add remove() tinymce instance back to LoadTinyTests. --- src/test/ts/browser/LoadTinyTest.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/test/ts/browser/LoadTinyTest.ts b/src/test/ts/browser/LoadTinyTest.ts index e789d46..54b345d 100644 --- a/src/test/ts/browser/LoadTinyTest.ts +++ b/src/test/ts/browser/LoadTinyTest.ts @@ -1,7 +1,7 @@ import { Assertions } from '@ephox/agar'; import { context, describe, it } from '@ephox/bedrock-client'; import { Global } from '@ephox/katamari'; -import { pRender } from '../alien/Loader'; +import { pRender, remove } from '../alien/Loader'; import { cleanupGlobalTinymce, VALID_API_KEY } from '../alien/TestHelper'; describe('LoadTinyTest', () => { @@ -20,6 +20,7 @@ describe('LoadTinyTest', () => { `); AssertTinymceVersion('7'); + remove(); cleanupGlobalTinymce(); }); @@ -32,6 +33,7 @@ describe('LoadTinyTest', () => { `); AssertTinymceVersion('6'); + remove(); cleanupGlobalTinymce(); }); @@ -44,6 +46,7 @@ describe('LoadTinyTest', () => { `); AssertTinymceVersion('5'); + remove(); cleanupGlobalTinymce(); }); @@ -56,6 +59,7 @@ describe('LoadTinyTest', () => { `); AssertTinymceVersion('4'); + remove(); cleanupGlobalTinymce(); }); @@ -73,6 +77,7 @@ describe('LoadTinyTest', () => { `https://cdn.tiny.cloud/1/${VALID_API_KEY}/tinymce/7-stable`, Global.tinymce.baseURI.source ); + remove(); cleanupGlobalTinymce(); }); @@ -90,6 +95,7 @@ describe('LoadTinyTest', () => { `https://cdn.tiny.cloud/1/${VALID_API_KEY}/tinymce/6-stable`, Global.tinymce.baseURI.source ); + remove(); cleanupGlobalTinymce(); }); @@ -107,6 +113,7 @@ describe('LoadTinyTest', () => { `https://cdn.tiny.cloud/1/${VALID_API_KEY}/tinymce/5-stable`, Global.tinymce.baseURI.source ); + remove(); cleanupGlobalTinymce(); }); }); From 75e680bd7faee5d0622962732f93ca1883359f1c Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Fri, 13 Sep 2024 15:26:27 +1000 Subject: [PATCH 11/17] Refactor EditorLoadTest.ts and related files --- .vscode/settings.json | 3 +- src/test/ts/browser/EditorLoadTest.ts | 51 ++++++++++++++------------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 306c494..7adc19f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "cSpell.words": [ "asynctest" - ] + ], + "typescript.tsdk": "node_modules/typescript/lib" } \ No newline at end of file diff --git a/src/test/ts/browser/EditorLoadTest.ts b/src/test/ts/browser/EditorLoadTest.ts index 6a82a8e..d660304 100644 --- a/src/test/ts/browser/EditorLoadTest.ts +++ b/src/test/ts/browser/EditorLoadTest.ts @@ -1,42 +1,43 @@ import { Assertions, UiFinder, Waiter } from '@ephox/agar'; -import { describe, beforeEach, afterEach, it } from '@ephox/bedrock-client'; +import { describe, beforeEach, afterEach, it, context } from '@ephox/bedrock-client'; import { Context } from 'vm'; import { getRoot, pRender, remove } from '../alien/Loader'; describe('Editor Component Tests', () => { - let context: Context; + let editorContext: Context; beforeEach(async () => { - context = await pRender(); + editorContext = await pRender(); }); afterEach(() => { remove(); }); + context('Editor Component Tests', () => { + it('should render the editor with the given data and template', async () => { + Assertions.assertEq('Vue instance should exist', true, !!editorContext.vm); + Assertions.assertEq('Vue instance should have a DOM element', true, editorContext.vm.$el instanceof window.HTMLElement); - it('should render the editor with the given data and template', async () => { - Assertions.assertEq('Vue instance should exist', true, !!context.vm); - Assertions.assertEq('Vue instance should have a DOM element', true, context.vm.$el instanceof window.HTMLElement); + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument + const textareaResult = UiFinder.findIn(editorContext.vm.$el, 'textarea'); + textareaResult.fold( + () => Assertions.assertEq('Textarea element should exist', true, false), + () => Assertions.assertEq('Textarea element should exist', true, true) + ); - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - const textareaResult = UiFinder.findIn(context.vm.$el, 'textarea'); - textareaResult.fold( - () => Assertions.assertEq('Textarea element should exist', true, false), - () => Assertions.assertEq('Textarea element should exist', true, true) - ); - - await Waiter.pTryUntil('Wait for the editor to load the skin', () => { - Assertions.assertEq('Editor instance should exist', true, !!context.editor); + await Waiter.pTryUntil('Wait for the editor to load the skin', () => { + Assertions.assertEq('Editor instance should exist', true, !!editorContext.editor); + }); }); - }); - it('should remove the editor component from the DOM', () => { - remove(); - const root = getRoot(); - Assertions.assertEq( - 'Root element should not contain any child nodes after removal', - true, - root.dom.childNodes.length === 0 - ); + it('should remove the editor component from the DOM', () => { + remove(); + const root = getRoot(); + Assertions.assertEq( + 'Root element should not contain any child nodes after removal', + true, + root.dom.childNodes.length === 0 + ); + }); }); -}); +}); \ No newline at end of file From c248a1fea3fa4c5d8c1dff657277d21d525230a9 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Fri, 13 Sep 2024 16:08:35 +1000 Subject: [PATCH 12/17] Removed EditorLoadTest.ts --- src/test/ts/browser/EditorLoadTest.ts | 43 --------------------------- 1 file changed, 43 deletions(-) delete mode 100644 src/test/ts/browser/EditorLoadTest.ts diff --git a/src/test/ts/browser/EditorLoadTest.ts b/src/test/ts/browser/EditorLoadTest.ts deleted file mode 100644 index d660304..0000000 --- a/src/test/ts/browser/EditorLoadTest.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Assertions, UiFinder, Waiter } from '@ephox/agar'; -import { describe, beforeEach, afterEach, it, context } from '@ephox/bedrock-client'; -import { Context } from 'vm'; -import { getRoot, pRender, remove } from '../alien/Loader'; - -describe('Editor Component Tests', () => { - let editorContext: Context; - - beforeEach(async () => { - editorContext = await pRender(); - }); - - afterEach(() => { - remove(); - }); - context('Editor Component Tests', () => { - it('should render the editor with the given data and template', async () => { - Assertions.assertEq('Vue instance should exist', true, !!editorContext.vm); - Assertions.assertEq('Vue instance should have a DOM element', true, editorContext.vm.$el instanceof window.HTMLElement); - - // eslint-disable-next-line @typescript-eslint/no-unsafe-argument - const textareaResult = UiFinder.findIn(editorContext.vm.$el, 'textarea'); - textareaResult.fold( - () => Assertions.assertEq('Textarea element should exist', true, false), - () => Assertions.assertEq('Textarea element should exist', true, true) - ); - - await Waiter.pTryUntil('Wait for the editor to load the skin', () => { - Assertions.assertEq('Editor instance should exist', true, !!editorContext.editor); - }); - }); - - it('should remove the editor component from the DOM', () => { - remove(); - const root = getRoot(); - Assertions.assertEq( - 'Root element should not contain any child nodes after removal', - true, - root.dom.childNodes.length === 0 - ); - }); - }); -}); \ No newline at end of file From 422c0cfb7acd262f03a6d373794f28e85aa274b9 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Thu, 26 Sep 2024 09:05:24 +1000 Subject: [PATCH 13/17] Update src/stories/Editor.stories.tsx Co-authored-by: tiny-ben-tran --- src/stories/Editor.stories.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/stories/Editor.stories.tsx b/src/stories/Editor.stories.tsx index 93d69f9..148525e 100644 --- a/src/stories/Editor.stories.tsx +++ b/src/stories/Editor.stories.tsx @@ -79,8 +79,6 @@ export const Iframe: Story = (args) => ({ }); const cc = args.channel || lastChannel; const conf = getConf(args.conf); - console.log('conf: ', conf); - console.log('channel: ', cc); return { apiKey, content, From 674abf6752bfb850352d82f5c20bbe1a28deddf8 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Thu, 26 Sep 2024 09:05:37 +1000 Subject: [PATCH 14/17] Update src/test/ts/browser/InitTest.ts Co-authored-by: tiny-ben-tran --- src/test/ts/browser/InitTest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ts/browser/InitTest.ts b/src/test/ts/browser/InitTest.ts index b1e16a9..0ca5371 100644 --- a/src/test/ts/browser/InitTest.ts +++ b/src/test/ts/browser/InitTest.ts @@ -1,6 +1,6 @@ import { Assertions, Keyboard, Keys, Waiter } from '@ephox/agar'; import { pRender, remove } from '../alien/Loader'; -import { VersionLoader } from '@tinymce/miniature'; // Add this line +import { VersionLoader } from '@tinymce/miniature'; import { SugarElement } from '@ephox/sugar'; import { describe, it, afterEach, before, context, after } from '@ephox/bedrock-client'; import { cleanupGlobalTinymce, VALID_API_KEY } from '../alien/TestHelper'; From 6bb5d8f1f41a7d0458ed7889335c20a06de33c71 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Wed, 16 Oct 2024 12:06:46 +1000 Subject: [PATCH 15/17] Refactor event name validation tests in UtilsTest, included comments. Removed Waiter from tests. Wrapped various func into beforeEach() to improve readability. --- src/test/ts/atomic/UtilsTest.ts | 22 +++++++++++++++------- src/test/ts/browser/InitTest.ts | 4 +--- src/test/ts/browser/LoadTinyTest.ts | 25 ++++++++++--------------- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/test/ts/atomic/UtilsTest.ts b/src/test/ts/atomic/UtilsTest.ts index 1de85c2..93066c7 100644 --- a/src/test/ts/atomic/UtilsTest.ts +++ b/src/test/ts/atomic/UtilsTest.ts @@ -5,18 +5,26 @@ import { isValidKey } from 'src/main/ts/Utils'; describe('UtilsTest', () => { const checkValidKey = (key: string, expected: boolean) => { const actual = isValidKey(key); - Assertions.assertEq('Key is valid', expected, actual); + Assertions.assertEq('Key should be valid in both camelCase and lowercase', expected, actual); }; - it('should check if key is valid onKeyUp', () => { - checkValidKey('onKeyUp', true); - }); + // eslint-disable-next-line max-len + // v-on event listeners inside DOM templates will be automatically transformed to lowercase (due to HTML’s case-insensitivity), so v-on:myEvent would become v-on:myevent. ref: https://eslint.vuejs.org/rules/custom-event-name-casing + + describe('Valid event name tests', () => { + const validKeys = [ + { key: 'onKeyUp', description: 'camelCase event name "onKeyUp"' }, + { key: 'onkeyup', description: 'lowercase event name "onkeyup"' } + ]; - it('should check if key is valid onkeyup', () => { - checkValidKey('onkeyup', true); + validKeys.forEach(({ key, description }) => { + it(`should validate ${description}`, () => { + checkValidKey(key, true); + }); + }); }); - it('should check if key is valid onDisable', () => { + it('should invalidate unknown event name "onDisable"', () => { checkValidKey('onDisable', false); }); }); \ No newline at end of file diff --git a/src/test/ts/browser/InitTest.ts b/src/test/ts/browser/InitTest.ts index 0ca5371..7efec3d 100644 --- a/src/test/ts/browser/InitTest.ts +++ b/src/test/ts/browser/InitTest.ts @@ -1,4 +1,4 @@ -import { Assertions, Keyboard, Keys, Waiter } from '@ephox/agar'; +import { Assertions, Keyboard, Keys } from '@ephox/agar'; import { pRender, remove } from '../alien/Loader'; import { VersionLoader } from '@tinymce/miniature'; import { SugarElement } from '@ephox/sugar'; @@ -62,7 +62,6 @@ describe('Editor Component Initialization Tests', () => { > `); await pFakeType('A', vmContext); - await Waiter.pWait(100); Assertions.assertEq('Content emitted should be of format="text"', 'A', vmContext.vm.content); }); @@ -78,7 +77,6 @@ describe('Editor Component Initialization Tests', () => { > `); await pFakeType('A', vmContext); - await Waiter.pWait(100); Assertions.assertEq('Content emitted should be of format="html"', '

A

', vmContext.vm.content); }); }); diff --git a/src/test/ts/browser/LoadTinyTest.ts b/src/test/ts/browser/LoadTinyTest.ts index 54b345d..ca5e452 100644 --- a/src/test/ts/browser/LoadTinyTest.ts +++ b/src/test/ts/browser/LoadTinyTest.ts @@ -1,5 +1,5 @@ import { Assertions } from '@ephox/agar'; -import { context, describe, it } from '@ephox/bedrock-client'; +import { beforeEach, context, describe, it } from '@ephox/bedrock-client'; import { Global } from '@ephox/katamari'; import { pRender, remove } from '../alien/Loader'; import { cleanupGlobalTinymce, VALID_API_KEY } from '../alien/TestHelper'; @@ -11,6 +11,12 @@ describe('LoadTinyTest', () => { }; context('LoadTinyTest', () => { + + beforeEach(() => { + remove(); + cleanupGlobalTinymce(); + }); + it('Should be able to load local version of TinyMCE 7 using the tinymceScriptSrc prop', async () => { await pRender({}, ` { `); AssertTinymceVersion('7'); - remove(); - cleanupGlobalTinymce(); }); it('Should be able to load local version of TinyMCE 6 using the tinymceScriptSrc prop', async () => { @@ -33,8 +37,6 @@ describe('LoadTinyTest', () => { `); AssertTinymceVersion('6'); - remove(); - cleanupGlobalTinymce(); }); it('Should be able to load local version of TinyMCE 5 using the tinymceScriptSrc prop', async () => { @@ -46,8 +48,6 @@ describe('LoadTinyTest', () => { `); AssertTinymceVersion('5'); - remove(); - cleanupGlobalTinymce(); }); it('Should be able to load local version of TinyMCE 4 using the tinymceScriptSrc prop', async () => { @@ -59,8 +59,6 @@ describe('LoadTinyTest', () => { `); AssertTinymceVersion('4'); - remove(); - cleanupGlobalTinymce(); }); it('Should be able to load TinyMCE 7 from Cloud', async () => { @@ -71,14 +69,13 @@ describe('LoadTinyTest', () => { cloud-channel="7-stable" > `); + AssertTinymceVersion('7'); Assertions.assertEq( 'TinyMCE 7 should have been loaded from Cloud', `https://cdn.tiny.cloud/1/${VALID_API_KEY}/tinymce/7-stable`, Global.tinymce.baseURI.source ); - remove(); - cleanupGlobalTinymce(); }); it('Should be able to load TinyMCE 6 from Cloud', async () => { @@ -89,14 +86,13 @@ describe('LoadTinyTest', () => { cloud-channel="6-stable" >
`); + AssertTinymceVersion('6'); Assertions.assertEq( 'TinyMCE 6 should have been loaded from Cloud', `https://cdn.tiny.cloud/1/${VALID_API_KEY}/tinymce/6-stable`, Global.tinymce.baseURI.source ); - remove(); - cleanupGlobalTinymce(); }); it('Should be able to load TinyMCE 5 from Cloud', async () => { @@ -107,14 +103,13 @@ describe('LoadTinyTest', () => { cloud-channel="5-stable" >
`); + AssertTinymceVersion('5'); Assertions.assertEq( 'TinyMCE 5 should have been loaded from Cloud', `https://cdn.tiny.cloud/1/${VALID_API_KEY}/tinymce/5-stable`, Global.tinymce.baseURI.source ); - remove(); - cleanupGlobalTinymce(); }); }); }); \ No newline at end of file From d5b7244dcb95121f0af5989c16c8fb6d2cecf822 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Mon, 21 Oct 2024 14:35:41 +1000 Subject: [PATCH 16/17] INT-3303: refine type definitions and standardize array iteration methods. --- src/test/ts/alien/Loader.ts | 3 ++- src/test/ts/atomic/UtilsTest.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/test/ts/alien/Loader.ts b/src/test/ts/alien/Loader.ts index 111fac7..53edd0f 100644 --- a/src/test/ts/alien/Loader.ts +++ b/src/test/ts/alien/Loader.ts @@ -18,7 +18,8 @@ const getRoot = () => SelectorFind.descendant(SugarBody.body(), '#root').getOrTh return root; }); -const pRender = (data: Record = {}, template: string = ``): Promise => new Promise((resolve) => { +// eslint-disable-next-line max-len +const pRender = (data: Record = {}, template: string = ``): Promise> => new Promise((resolve) => { const root = getRoot(); const mountPoint = SugarElement.fromTag('div'); Insert.append(root, mountPoint); diff --git a/src/test/ts/atomic/UtilsTest.ts b/src/test/ts/atomic/UtilsTest.ts index 93066c7..e0455c1 100644 --- a/src/test/ts/atomic/UtilsTest.ts +++ b/src/test/ts/atomic/UtilsTest.ts @@ -1,5 +1,6 @@ import { Assertions } from '@ephox/agar'; import { describe, it } from '@ephox/bedrock-client'; +import { Arr } from '@ephox/katamari'; import { isValidKey } from 'src/main/ts/Utils'; describe('UtilsTest', () => { @@ -17,7 +18,7 @@ describe('UtilsTest', () => { { key: 'onkeyup', description: 'lowercase event name "onkeyup"' } ]; - validKeys.forEach(({ key, description }) => { + Arr.each(validKeys, ({ key, description }) => { it(`should validate ${description}`, () => { checkValidKey(key, true); }); From e5046b04be89f982339408d6a9c7ff8b15df9350 Mon Sep 17 00:00:00 2001 From: Karl Kemister-Sheppard Date: Mon, 21 Oct 2024 14:51:44 +1000 Subject: [PATCH 17/17] Update src/test/ts/alien/TestHelper.ts --- src/test/ts/alien/TestHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ts/alien/TestHelper.ts b/src/test/ts/alien/TestHelper.ts index e1e38d8..1505ab1 100644 --- a/src/test/ts/alien/TestHelper.ts +++ b/src/test/ts/alien/TestHelper.ts @@ -7,7 +7,7 @@ const VALID_API_KEY = 'qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc'; // Function to clean up and remove TinyMCE-related scripts and links from the document const cleanupGlobalTinymce = () => { ScriptLoader.reinitialize(); - // Delete global references to TinyMCE, if they exist + // This deletes global references to TinyMCE, to ensure a clean slate for each initialization when tests are switching to a different editor versions. delete Global.tinymce; delete Global.tinyMCE; // Helper function to check if an element has a TinyMCE-related URI in a specific attribute