Skip to content

Commit ccc0099

Browse files
INT-3303: Update Vue integration tests to use BDD style. (#434)
* INT-3303: Convert existing test.ts files to use bdd-styling conventions. * create TestHelper.ts to isolate variables update imports * remove async from cFakeType function. * Add test to LoadTinyTest.ts for loading from scriptSrc and Cloud. * INT-3303: Convert cFakeType to asynchronous. * INT-3303: Refactor InitTest.ts and related files. * add loop to iterate each editor version for tests. * afterEach function was added inside the loop for different versions. * INT-3303: Fix defaultValue warning. update cleanupTinymce to cleanupGlobalTinymce to be more specific. fix spacing between tests. add afterEach to context function. * INT-3303: add remove() tinymce instance back to LoadTinyTests. * Refactor EditorLoadTest.ts and related files * Removed EditorLoadTest.ts * Update src/stories/Editor.stories.tsx Co-authored-by: tiny-ben-tran <[email protected]> * Update src/test/ts/browser/InitTest.ts Co-authored-by: tiny-ben-tran <[email protected]> * Refactor event name validation tests in UtilsTest, included comments. Removed Waiter from tests. Wrapped various func into beforeEach() to improve readability. * INT-3303: refine type definitions and standardize array iteration methods. * Update src/test/ts/alien/TestHelper.ts --------- Co-authored-by: tiny-ben-tran <[email protected]>
1 parent 28169fa commit ccc0099

File tree

7 files changed

+244
-210
lines changed

7 files changed

+244
-210
lines changed

.vscode/settings.json

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"cSpell.words": [
3+
"asynctest"
4+
],
5+
"typescript.tsdk": "node_modules/typescript/lib"
6+
}

src/stories/Editor.stories.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export default {
5252
table: {
5353
defaultValue: {summary: '5'}
5454
},
55-
defaultValue: ['7'],
55+
defaultValue: '7',
5656
options: ['5', '5-dev', '5-testing', '6-testing', '6-stable', '7-dev', '7-testing', '7-stable'],
5757
control: { type: 'select'}
5858
},
@@ -79,7 +79,6 @@ export const Iframe: Story = (args) => ({
7979
});
8080
const cc = args.channel || lastChannel;
8181
const conf = getConf(args.conf);
82-
console.log('conf: ', conf);
8382
return {
8483
apiKey,
8584
content,

src/test/ts/alien/Loader.ts

+33-34
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { Chain } from '@ephox/agar';
21
import { Fun } from '@ephox/katamari';
32
import { Attribute, SugarBody, SugarElement, Insert, Remove, SelectorFind } from '@ephox/sugar';
43
import Editor from 'src/main/ts/index';
@@ -19,40 +18,40 @@ const getRoot = () => SelectorFind.descendant(SugarBody.body(), '#root').getOrTh
1918
return root;
2019
});
2120

22-
const cRender = (data: Record<string, any> = {}, template: string = `<editor :init="init" ></editor>`) =>
23-
Chain.async<Context, Context>((_value, next, _die) => {
24-
const root = getRoot();
25-
const mountPoint = SugarElement.fromTag('div');
26-
Insert.append(root, mountPoint);
27-
28-
const originalInit = data.init || {};
29-
const originalSetup = originalInit.setup || Fun.noop;
30-
31-
const vm = createApp({
32-
template,
33-
components: {
34-
Editor
35-
},
36-
data: () => ({
37-
...data,
38-
outputFormat: 'text',
39-
init: {
40-
...originalInit,
41-
setup: (editor: any) => {
42-
originalSetup(editor);
43-
editor.on('SkinLoaded', () => {
44-
setTimeout(() => {
45-
next({ editor, vm });
46-
}, 0);
47-
});
48-
}
21+
// eslint-disable-next-line max-len
22+
const pRender = (data: Record<string, any> = {}, template: string = `<editor :init="init"></editor>`): Promise<Record<string, any>> => new Promise((resolve) => {
23+
const root = getRoot();
24+
const mountPoint = SugarElement.fromTag('div');
25+
Insert.append(root, mountPoint);
26+
27+
const originalInit = data.init || {};
28+
const originalSetup = originalInit.setup || Fun.noop;
29+
30+
const vm = createApp({
31+
template,
32+
components: {
33+
Editor
34+
},
35+
data: () => ({
36+
...data,
37+
outputFormat: 'text',
38+
init: {
39+
...originalInit,
40+
setup: (editor: any) => {
41+
originalSetup(editor);
42+
editor.on('SkinLoaded', () => {
43+
setTimeout(() => {
44+
resolve({ editor, vm });
45+
}, 0);
46+
});
4947
}
50-
}),
51-
}).mount(mountPoint.dom);
52-
});
48+
}
49+
}),
50+
}).mount(mountPoint.dom);
51+
});
5352

54-
const cRemove = Chain.op(() => {
53+
const remove = () => {
5554
Remove.remove(getRoot());
56-
});
55+
};
5756

58-
export { cRender, cRemove };
57+
export { pRender, remove, getRoot };

src/test/ts/alien/TestHelper.ts

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { Global, Strings, Arr } from '@ephox/katamari';
2+
import { SugarElement, Attribute, SelectorFilter, Remove } from '@ephox/sugar';
3+
import { ScriptLoader } from '../../../main/ts/ScriptLoader';
4+
5+
const VALID_API_KEY = 'qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc';
6+
7+
// Function to clean up and remove TinyMCE-related scripts and links from the document
8+
const cleanupGlobalTinymce = () => {
9+
ScriptLoader.reinitialize();
10+
// This deletes global references to TinyMCE, to ensure a clean slate for each initialization when tests are switching to a different editor versions.
11+
delete Global.tinymce;
12+
delete Global.tinyMCE;
13+
// Helper function to check if an element has a TinyMCE-related URI in a specific attribute
14+
const hasTinymceUri = (attrName: string) => (elm: SugarElement<Element>) =>
15+
Attribute.getOpt(elm, attrName).exists((src) => Strings.contains(src, 'tinymce'));
16+
// Find all script and link elements that have a TinyMCE-related URI
17+
const elements = Arr.flatten([
18+
Arr.filter(SelectorFilter.all('script'), hasTinymceUri('src')),
19+
Arr.filter(SelectorFilter.all('link'), hasTinymceUri('href')),
20+
]);
21+
Arr.each(elements, Remove.remove);
22+
};
23+
24+
export {
25+
VALID_API_KEY,
26+
cleanupGlobalTinymce,
27+
};

src/test/ts/atomic/UtilsTest.ts

+23-7
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,31 @@
11
import { Assertions } from '@ephox/agar';
2-
import { UnitTest } from '@ephox/bedrock-client';
2+
import { describe, it } from '@ephox/bedrock-client';
3+
import { Arr } from '@ephox/katamari';
34
import { isValidKey } from 'src/main/ts/Utils';
45

5-
UnitTest.test('UtilsTest', () => {
6-
6+
describe('UtilsTest', () => {
77
const checkValidKey = (key: string, expected: boolean) => {
88
const actual = isValidKey(key);
9-
Assertions.assertEq('Key is valid', expected, actual);
9+
Assertions.assertEq('Key should be valid in both camelCase and lowercase', expected, actual);
1010
};
1111

12-
checkValidKey('onKeyUp', true);
13-
checkValidKey('onkeyup', true);
14-
checkValidKey('onDisable', false);
12+
// eslint-disable-next-line max-len
13+
// 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
14+
15+
describe('Valid event name tests', () => {
16+
const validKeys = [
17+
{ key: 'onKeyUp', description: 'camelCase event name "onKeyUp"' },
18+
{ key: 'onkeyup', description: 'lowercase event name "onkeyup"' }
19+
];
20+
21+
Arr.each(validKeys, ({ key, description }) => {
22+
it(`should validate ${description}`, () => {
23+
checkValidKey(key, true);
24+
});
25+
});
26+
});
27+
28+
it('should invalidate unknown event name "onDisable"', () => {
29+
checkValidKey('onDisable', false);
30+
});
1531
});

src/test/ts/browser/InitTest.ts

+75-74
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,84 @@
1-
import { GeneralSteps, Logger, Pipeline, Assertions, Chain, Keyboard, Keys } from '@ephox/agar';
2-
import { UnitTest } from '@ephox/bedrock-client';
1+
import { Assertions, Keyboard, Keys } from '@ephox/agar';
2+
import { pRender, remove } from '../alien/Loader';
33
import { VersionLoader } from '@tinymce/miniature';
4-
import { cRender, cRemove } from '../alien/Loader';
54
import { SugarElement } from '@ephox/sugar';
5+
import { describe, it, afterEach, before, context, after } from '@ephox/bedrock-client';
6+
import { cleanupGlobalTinymce, VALID_API_KEY } from '../alien/TestHelper';
7+
import { Arr } from '@ephox/katamari';
68

7-
UnitTest.asynctest('InitTest', (success, failure) => {
8-
const cFakeType = (str: string) => Chain.op((context: any) => {
9-
context.editor.getBody().innerHTML = '<p>' + str + '</p>';
10-
Keyboard.keystroke(Keys.space(), {}, SugarElement.fromDom(context.editor.getBody()) as SugarElement<Node>);
11-
});
9+
describe('Editor Component Initialization Tests', () => {
10+
// eslint-disable-next-line @typescript-eslint/require-await
11+
const pFakeType = async (str: string, vmContext: any) => {
12+
vmContext.editor.getBody().innerHTML = '<p>' + str + '</p>';
13+
Keyboard.keystroke(Keys.space(), {}, SugarElement.fromDom(vmContext.editor.getBody()) as SugarElement<Node>);
14+
};
15+
16+
Arr.each([ '4', '5', '6', '7' as const ], (version) => {
17+
context(`Version: ${version}`, () => {
18+
19+
before(async () => {
20+
await VersionLoader.pLoadVersion(version);
21+
});
1222

13-
const sTestVersion = (version: '4' | '5' | '6' | '7') => VersionLoader.sWithVersion(
14-
version,
15-
GeneralSteps.sequence([
16-
Logger.t('Should be able to setup editor', Chain.asStep({}, [
17-
cRender(),
18-
Chain.op((context) => {
19-
Assertions.assertEq('Editor should not be inline', false, context.editor.inline);
20-
}),
21-
cRemove
22-
])),
23+
after(() => {
24+
cleanupGlobalTinymce();
25+
});
2326

24-
Logger.t('Should be able to setup editor', Chain.asStep({}, [
25-
cRender({}, `<editor :init="init" :inline=true ></editor>`),
26-
Chain.op((context) => {
27-
Assertions.assertEq('Editor should be inline', true, context.editor.inline);
28-
}),
29-
cRemove
30-
])),
27+
afterEach(() => {
28+
remove();
29+
});
3130

32-
Logger.t('Should be able to setup editor', Chain.asStep({}, [
33-
cRender({ init: { inline: true }}),
34-
Chain.op((context) => {
35-
Assertions.assertEq('Editor should be inline', true, context.editor.inline);
36-
}),
37-
cRemove
38-
])),
31+
it('should not be inline by default', async () => {
32+
const vmContext = await pRender({}, `
33+
<editor
34+
:init="init"
35+
></editor>`);
36+
Assertions.assertEq('Editor should not be inline', false, vmContext.editor.inline);
37+
});
3938

40-
Logger.t('Test one way binding tinymce-vue -> variable', GeneralSteps.sequence([
41-
Logger.t('Test outputFormat="text"', Chain.asStep({}, [
42-
cRender({
43-
content: undefined
44-
}, `
45-
<editor
46-
:init="init"
47-
@update:modelValue="content = $event"
48-
output-format="text"
49-
></editor>
50-
`),
51-
cFakeType('A'),
52-
Chain.op((context) => {
53-
Assertions.assertEq('Content emitted should be of format="text"', 'A', context.vm.content);
54-
}),
55-
cRemove
56-
])),
57-
Logger.t('Test outputFormat="html"', Chain.asStep({}, [
58-
cRender({
59-
content: undefined
60-
}, `
61-
<editor
62-
:init="init"
63-
v-model="content"
64-
output-format="html"
65-
></editor>
66-
`),
67-
cFakeType('A'),
68-
Chain.op((context) => {
69-
Assertions.assertEq('Content emitted should be of format="html"', '<p>A</p>', context.vm.content);
70-
}),
71-
cRemove
72-
])),
73-
])),
74-
])
75-
);
39+
it('should be inline with inline attribute in template', async () => {
40+
const vmContext = await pRender({}, `
41+
<editor
42+
:init="init"
43+
:inline="true"
44+
></editor>`);
45+
Assertions.assertEq('Editor should be inline', true, vmContext.editor.inline);
46+
});
7647

77-
Pipeline.async({}, [
78-
sTestVersion('4'),
79-
sTestVersion('5'),
80-
sTestVersion('6'),
81-
sTestVersion('7'),
82-
], success, failure);
48+
it('should be inline with inline option in init', async () => {
49+
const vmContext = await pRender({ init: { inline: true }});
50+
Assertions.assertEq('Editor should be inline', true, vmContext.editor.inline);
51+
});
52+
53+
it('should handle one-way binding with output-format="text"', async () => {
54+
const vmContext = await pRender({
55+
content: undefined,
56+
}, `
57+
<editor
58+
:init="init"
59+
api-key="${VALID_API_KEY}"
60+
@update:modelValue="content=$event"
61+
output-format="text"
62+
></editor>
63+
`);
64+
await pFakeType('A', vmContext);
65+
Assertions.assertEq('Content emitted should be of format="text"', 'A', vmContext.vm.content);
66+
});
67+
68+
it('should handle one-way binding with output-format="html"', async () => {
69+
const vmContext = await pRender({
70+
content: undefined,
71+
}, `
72+
<editor
73+
:init="init"
74+
api-key="${VALID_API_KEY}"
75+
@update:modelValue="content=$event"
76+
output-format="html"
77+
></editor>
78+
`);
79+
await pFakeType('A', vmContext);
80+
Assertions.assertEq('Content emitted should be of format="html"', '<p>A</p>', vmContext.vm.content);
81+
});
82+
});
83+
});
8384
});

0 commit comments

Comments
 (0)