Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

INT-3303: Update Vue integration tests to use BDD style. #434

Merged
merged 19 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
c0cdbb0
INT-3303: Convert existing test.ts files to use bdd-styling conventions.
kemister85 Sep 6, 2024
10c68a4
create TestHelper.ts to isolate variables
kemister85 Sep 8, 2024
bb56803
remove async from cFakeType function.
kemister85 Sep 9, 2024
a5a9a6d
Add test to LoadTinyTest.ts for loading from scriptSrc and Cloud.
kemister85 Sep 9, 2024
38ba52b
INT-3303: Convert cFakeType to asynchronous.
kemister85 Sep 11, 2024
105e1fa
INT-3303: Refactor InitTest.ts and related files.
kemister85 Sep 11, 2024
6d1df84
add loop to iterate each editor version for tests.
kemister85 Sep 12, 2024
e71bef9
afterEach function was added inside the loop for different versions.
kemister85 Sep 12, 2024
b9ff917
INT-3303: Fix defaultValue warning.
kemister85 Sep 13, 2024
3d79292
INT-3303: add remove() tinymce instance back to LoadTinyTests.
kemister85 Sep 13, 2024
c38658d
Merge branch 'main' into feature/INT-3303
kemister85 Sep 13, 2024
75e680b
Refactor EditorLoadTest.ts and related files
kemister85 Sep 13, 2024
c248a1f
Removed EditorLoadTest.ts
kemister85 Sep 13, 2024
422c0cf
Update src/stories/Editor.stories.tsx
kemister85 Sep 25, 2024
674abf6
Update src/test/ts/browser/InitTest.ts
kemister85 Sep 25, 2024
6bb5d8f
Refactor event name validation tests in UtilsTest, included comments.
kemister85 Oct 16, 2024
d5b7244
INT-3303: refine type definitions and standardize array iteration met…
kemister85 Oct 21, 2024
e5046b0
Update src/test/ts/alien/TestHelper.ts
kemister85 Oct 21, 2024
63fe7c5
Merge branch 'main' into feature/INT-3303
kemister85 Oct 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"cSpell.words": [
"asynctest"
],
"typescript.tsdk": "node_modules/typescript/lib"
}
3 changes: 1 addition & 2 deletions src/stories/Editor.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'}
},
Expand All @@ -79,7 +79,6 @@ export const Iframe: Story = (args) => ({
});
const cc = args.channel || lastChannel;
const conf = getConf(args.conf);
console.log('conf: ', conf);
return {
apiKey,
content,
Expand Down
67 changes: 33 additions & 34 deletions src/test/ts/alien/Loader.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -19,40 +18,40 @@ const getRoot = () => SelectorFind.descendant(SugarBody.body(), '#root').getOrTh
return root;
});

const cRender = (data: Record<string, any> = {}, template: string = `<editor :init="init" ></editor>`) =>
Chain.async<Context, Context>((_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);
});
}
// eslint-disable-next-line max-len
const pRender = (data: Record<string, any> = {}, template: string = `<editor :init="init"></editor>`): Promise<Record<string, any>> => 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,
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 };
export { pRender, remove, getRoot };
27 changes: 27 additions & 0 deletions src/test/ts/alien/TestHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
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 cleanupGlobalTinymce = () => {
ScriptLoader.reinitialize();
// 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
const hasTinymceUri = (attrName: string) => (elm: SugarElement<Element>) =>
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,
cleanupGlobalTinymce,
};
30 changes: 23 additions & 7 deletions src/test/ts/atomic/UtilsTest.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,31 @@
import { Assertions } from '@ephox/agar';
import { UnitTest } from '@ephox/bedrock-client';
import { describe, it } from '@ephox/bedrock-client';
import { Arr } from '@ephox/katamari';
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);
Assertions.assertEq('Key should be valid in both camelCase and lowercase', expected, actual);
};

checkValidKey('onKeyUp', true);
checkValidKey('onkeyup', true);
checkValidKey('onDisable', false);
// 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"' }
];

Arr.each(validKeys, ({ key, description }) => {
it(`should validate ${description}`, () => {
checkValidKey(key, true);
});
});
});

it('should invalidate unknown event name "onDisable"', () => {
checkValidKey('onDisable', false);
});
});
149 changes: 75 additions & 74 deletions src/test/ts/browser/InitTest.ts
Original file line number Diff line number Diff line change
@@ -1,83 +1,84 @@
import { GeneralSteps, Logger, Pipeline, Assertions, Chain, Keyboard, Keys } from '@ephox/agar';
import { UnitTest } from '@ephox/bedrock-client';
import { Assertions, Keyboard, Keys } from '@ephox/agar';
import { pRender, remove } from '../alien/Loader';
import { VersionLoader } from '@tinymce/miniature';
import { cRender, cRemove } from '../alien/Loader';
import { SugarElement } from '@ephox/sugar';
import { describe, it, afterEach, before, context, after } from '@ephox/bedrock-client';
import { cleanupGlobalTinymce, VALID_API_KEY } from '../alien/TestHelper';
import { Arr } from '@ephox/katamari';

UnitTest.asynctest('InitTest', (success, failure) => {
const cFakeType = (str: string) => Chain.op((context: any) => {
context.editor.getBody().innerHTML = '<p>' + str + '</p>';
Keyboard.keystroke(Keys.space(), {}, SugarElement.fromDom(context.editor.getBody()) as SugarElement<Node>);
});
describe('Editor Component Initialization Tests', () => {
// eslint-disable-next-line @typescript-eslint/require-await
const pFakeType = async (str: string, vmContext: any) => {
vmContext.editor.getBody().innerHTML = '<p>' + str + '</p>';
Keyboard.keystroke(Keys.space(), {}, SugarElement.fromDom(vmContext.editor.getBody()) as SugarElement<Node>);
};

Arr.each([ '4', '5', '6', '7' as const ], (version) => {
context(`Version: ${version}`, () => {

before(async () => {
await VersionLoader.pLoadVersion(version);
});

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
])),
after(() => {
cleanupGlobalTinymce();
});

Logger.t('Should be able to setup editor', Chain.asStep({}, [
cRender({}, `<editor :init="init" :inline=true ></editor>`),
Chain.op((context) => {
Assertions.assertEq('Editor should be inline', true, context.editor.inline);
}),
cRemove
])),
afterEach(() => {
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 not be inline by default', async () => {
const vmContext = await pRender({}, `
<editor
:init="init"
></editor>`);
Assertions.assertEq('Editor should not be inline', false, vmContext.editor.inline);
});

Logger.t('Test one way binding tinymce-vue -> variable', GeneralSteps.sequence([
Logger.t('Test outputFormat="text"', Chain.asStep({}, [
cRender({
content: undefined
}, `
<editor
:init="init"
@update:modelValue="content = $event"
output-format="text"
></editor>
`),
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
}, `
<editor
:init="init"
v-model="content"
output-format="html"
></editor>
`),
cFakeType('A'),
Chain.op((context) => {
Assertions.assertEq('Content emitted should be of format="html"', '<p>A</p>', context.vm.content);
}),
cRemove
])),
])),
])
);
it('should be inline with inline attribute in template', async () => {
const vmContext = await pRender({}, `
<editor
:init="init"
:inline="true"
></editor>`);
Assertions.assertEq('Editor should be inline', true, vmContext.editor.inline);
});

Pipeline.async({}, [
sTestVersion('4'),
sTestVersion('5'),
sTestVersion('6'),
sTestVersion('7'),
], success, failure);
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,
}, `
<editor
:init="init"
api-key="${VALID_API_KEY}"
@update:modelValue="content=$event"
output-format="text"
></editor>
`);
await pFakeType('A', vmContext);
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,
}, `
<editor
:init="init"
api-key="${VALID_API_KEY}"
@update:modelValue="content=$event"
output-format="html"
></editor>
`);
await pFakeType('A', vmContext);
Assertions.assertEq('Content emitted should be of format="html"', '<p>A</p>', vmContext.vm.content);
});
});
});
});
Loading
Loading