瀏覽代碼

Add tests for new mention API and update manual tests.

Maciej Gołaszewski 6 年之前
父節點
當前提交
7b5a38bdaa

+ 8 - 2
packages/ckeditor5-mention/src/mentionui.js

@@ -299,7 +299,9 @@ export default class MentionUI extends Plugin {
 					this._items.clear();
 
 					for ( const feedItem of feed ) {
-						const item = typeof feedItem != 'object' ? { id: marker + feedItem, text: feedItem } : feedItem;
+						const fullId = marker + feedItem;
+
+						const item = typeof feedItem != 'object' ? { id: fullId, text: fullId } : feedItem;
 
 						this._items.add( { item, marker } );
 					}
@@ -538,7 +540,11 @@ function createFeedCallback( feedItems ) {
 		const filteredItems = feedItems
 		// Make default mention feed case-insensitive.
 			.filter( item => {
-				return ( typeof item == 'string' ? item : String( item.id ) ).toLowerCase().includes( feedText.toLowerCase() );
+				// Item might be defined as object.
+				const itemId = typeof item == 'string' ? item : String( item.id );
+
+				// The default feed is case insensitive.
+				return itemId.toLowerCase().includes( feedText.toLowerCase() );
 			} )
 			// Do not return more than 10 items.
 			.slice( 0, 10 );

+ 11 - 0
packages/ckeditor5-mention/tests/manual/mention-custom-renderer.js

@@ -38,6 +38,17 @@ ClassicEditor
 
 						return span;
 					}
+				},
+				{
+					marker: '#',
+					feed: [
+						{ id: '1002', text: 'Some bug in editor' },
+						{ id: '1003', text: 'Introduce this feature' },
+						{ id: '1004', text: 'Missing docs' },
+						{ id: '1005', text: 'Another bug' },
+						{ id: '1006', text: 'More bugs' }
+					],
+					itemRenderer: item => `Issue ${ item.id }: ${ item.text }`
 				}
 			]
 		}

+ 17 - 8
packages/ckeditor5-mention/tests/manual/mention-custom-renderer.md

@@ -4,16 +4,25 @@ The mention configuration with custom item renderer for autocomplete list.
 
 ### Configuration
 
-The list is returned in promise (no timeout) and is filtered for any match of `name` and `username` (custom feed):
+The feeds:
 
-The feed:
-- `{ id: '1', name: 'Barney Stinson', username: 'swarley' }`
-- `{ id: '2', name: 'Lily Aldrin', username: 'lilypad' }`
-- `{ id: '3', name: 'Marshall Eriksen', username: 'marshmallow' }`
-- `{ id: '4', name: 'Robin Scherbatsky', username: 'rsparkles' }`
-- `{ id: '5', name: 'Ted Mosby', username: 'tdog' }`
+1. The list is returned in promise (no timeout) and is filtered for any match of `name` and `username` (custom feed):
+    - `{ itemId: '1', name: 'Barney Stinson', id: '@swarley' }`
+    - `{ itemId: '2', name: 'Lily Aldrin', id: '@lilypad' }`
+    - `{ itemId: '3', name: 'Marshall Eriksen', id: '@marshmallow' }`
+    - `{ itemId: '4', name: 'Robin Scherbatsky', id: '@rsparkles' }`
+    - `{ itemId: '5', name: 'Ted Mosby', id: '@tdog' }`
 
-The item is rendered as `<span>` instead of default button.
+    The items are rendered as `<span>` instead of default button.
+
+2. Static list of issues with item renderer that returns a string:
+    - `{ id: '1002', text: 'Some bug in editor' }`
+    - `{ id: '1003', text: 'Introduce this feature' }`
+    - `{ id: '1004', text: 'Missing docs' }`
+    - `{ id: '1005', text: 'Another bug' }`
+    - `{ id: '1006', text: 'More bugs' }`
+
+    This feed will create mention with `text` (as it is defined for item) instead of `id`.
 
 ### Interaction
 

+ 2 - 2
packages/ckeditor5-mention/tests/manual/mention-custom-view.html

@@ -1,7 +1,7 @@
 <div id="editor">
-	<p>Have you met... <a class="mention" data-mention="@Ted Mosby" href="https://www.imdb.com/title/tt0460649/characters/nm1102140">@Ted Mosby</a></p>
+	<p>Have you met... <a class="mention" data-mention="@Ted Mosby" href="https://www.imdb.com/title/tt0460649/characters/nm1102140">Ted Mosby</a></p>
 
-	<p>Same mention twice in data: <a class="mention" data-mention="@Ted Mosby" href="https://www.imdb.com/title/tt0460649/characters/nm1102140">@Ted Mosby</a><a class="mention" data-mention="@Ted Mosby" href="https://www.imdb.com/title/tt0460649/characters/nm1102140">@Ted Mosby</a></p>
+	<p>Same mention twice in data: <a class="mention" data-mention="@Ted Mosby" href="https://www.imdb.com/title/tt0460649/characters/nm1102140">Ted Mosby</a><a class="mention" data-mention="@Ted Mosby" href="https://www.imdb.com/title/tt0460649/characters/nm1102140">Ted Mosby</a></p>
 </div>
 
 <style>

+ 5 - 15
packages/ckeditor5-mention/tests/manual/mention-custom-view.js

@@ -81,21 +81,11 @@ ClassicEditor
 
 function getFeed( feedText ) {
 	return [
-		{ itemId: '1', id: '@Barney Stinson', text: 'Barney Stinson', link: 'https://www.imdb.com/title/tt0460649/characters/nm0000439' },
-		{ itemId: '2', id: '@Lily Aldrin', text: 'Lily Aldrin', link: 'https://www.imdb.com/title/tt0460649/characters/nm0004989' },
-		{
-			itemId: '3',
-			id: '@Marshall Eriksen',
-			text: 'Marshall Eriksen',
-			link: 'https://www.imdb.com/title/tt0460649/characters/nm0781981'
-		},
-		{
-			itemId: '4',
-			id: '@Robin Scherbatsky',
-			text: 'Robin Scherbatsky',
-			link: 'https://www.imdb.com/title/tt0460649/characters/nm1130627'
-		},
-		{ itemId: '5', id: '@Ted Mosby', text: 'Ted Mosby', link: 'https://www.imdb.com/title/tt0460649/characters/nm1102140' }
+		{ id: '@Barney Stinson', text: 'Barney Stinson', link: 'https://www.imdb.com/title/tt0460649/characters/nm0000439' },
+		{ id: '@Lily Aldrin', text: 'Lily Aldrin', link: 'https://www.imdb.com/title/tt0460649/characters/nm0004989' },
+		{ id: '@Marshall Eriksen', text: 'Marshall Eriksen', link: 'https://www.imdb.com/title/tt0460649/characters/nm0781981' },
+		{ id: '@Robin Scherbatsky', text: 'Robin Scherbatsky', link: 'https://www.imdb.com/title/tt0460649/characters/nm1130627' },
+		{ id: '@Ted Mosby', text: 'Ted Mosby', link: 'https://www.imdb.com/title/tt0460649/characters/nm1102140' }
 	].filter( item => {
 		const searchString = feedText.toLowerCase();
 

+ 5 - 5
packages/ckeditor5-mention/tests/manual/mention-custom-view.md

@@ -5,11 +5,11 @@ This sample overrides default mention conversion to `<span>`. The mention is con
 ### Configuration
 
 The feed:
-- `{ name: 'Barney Stinson', link: 'https://www.imdb.com/title/tt0460649/characters/nm0000439' }`
-- `{ name: 'Lily Aldrin', link: 'https://www.imdb.com/title/tt0460649/characters/nm0004989?ref_=tt_cl_t5' }`
-- `{ name: 'Marshall Eriksen', link: 'https://www.imdb.com/title/tt0460649/characters/nm0781981' }`
-- `{ name: 'Robin Scherbatsky', link: 'https://www.imdb.com/title/tt0460649/characters/nm1130627' }`
-- `{ name: 'Ted Mosby', link: 'https://www.imdb.com/title/tt0460649/characters/nm1102140' }`
+- `{ id: '@Barney Stinson', text: 'Barney Stinson', link: 'https://www.imdb.com/title/tt0460649/characters/nm0000439' }`
+- `{ id: '@Lily Aldrin', text: 'Lily Aldrin', link: 'https://www.imdb.com/title/tt0460649/characters/nm0004989?ref_=tt_cl_t5' }`
+- `{ id: '@Marshall Eriksen', text: 'Marshall Eriksen', link: 'https://www.imdb.com/title/tt0460649/characters/nm0781981' }`
+- `{ id: '@Robin Scherbatsky', text: 'Robin Scherbatsky', link: 'https://www.imdb.com/title/tt0460649/characters/nm1130627' }`
+- `{ id: '@Ted Mosby', text: 'Ted Mosby', link: 'https://www.imdb.com/title/tt0460649/characters/nm1102140' }`
 
 ### Interaction
 

+ 2 - 2
packages/ckeditor5-mention/tests/manual/mention.html

@@ -1,4 +1,4 @@
 <div id="editor">
-	<p>Hello <span class="mention" data-mention="@Ted">Ted</span>.</p>
-	<p>Hello <span class="mention" data-mention="@Ted">Ted</span><span class="mention" data-mention="@Ted">Ted</span>.</p>
+	<p>Hello <span class="mention" data-mention="@Ted">@Ted</span>.</p>
+	<p>Hello <span class="mention" data-mention="@Ted">@Ted</span><span class="mention" data-mention="@Ted">@Ted</span>.</p>
 </div>

+ 1 - 7
packages/ckeditor5-mention/tests/manual/mention.js

@@ -27,13 +27,7 @@ ClassicEditor
 		mention: {
 			feeds: [
 				{
-					feed: [
-						{ id: '@Barney', label: 'The Barney', text: 'Barney' },
-						{ id: '@Lily', label: 'The Lily', text: 'Lily' },
-						{ id: '@Marshall', label: 'The Marshall', text: 'Marshall' },
-						{ id: '@Robin', label: 'The Robin', text: 'Robin' },
-						{ id: '@Ted', label: 'The Ted', text: 'Ted' } ],
-					itemRenderer: item => item.label
+					feed: [ 'Barney', 'Lily', 'Marshall', 'Robin', 'Ted' ]
 				},
 				{
 					marker: '#',

+ 4 - 1
packages/ckeditor5-mention/tests/manual/mention.md

@@ -7,15 +7,18 @@ The minimal mention configuration with a static list of autocomplete feed:
 The feeds:
 
 1. Static list with `@` marker:
+
     - Barney
     - Lily
     - Marshall
     - Robin
     - Ted
+
 2. Static list of 20 items (`#` marker)
+
     - a01
     - a02
-    - ... 
+    - ...
     - a20
 
 ### Interaction

+ 122 - 4
packages/ckeditor5-mention/tests/mentionui.js

@@ -760,7 +760,8 @@ describe( 'MentionUI', () => {
 		} );
 
 		describe( 'default list item', () => {
-			const feedItems = staticConfig.feeds[ 0 ].feed.map( text => ( { text, id: `@${ text }` } ) );
+			// Create map of expected feed items as objects as they will be stored internally.
+			const feedItems = staticConfig.feeds[ 0 ].feed.map( text => ( { text: `@${ text }`, id: `@${ text }` } ) );
 
 			beforeEach( () => {
 				return createClassicTestEditor( staticConfig );
@@ -851,7 +852,7 @@ describe( 'MentionUI', () => {
 				{ id: '@Barney' },
 				{ id: '@Robin' },
 				{ id: '@Lily' },
-				{ id: '@Marhsal' }
+				{ id: '@Marshal' }
 			];
 
 			beforeEach( () => {
@@ -881,7 +882,124 @@ describe( 'MentionUI', () => {
 			} );
 		} );
 
-		describe( 'custom list item', () => {
+		describe( 'custom list item (string)', () => {
+			const issues = [
+				{ id: '1002', title: 'Some bug in editor.' },
+				{ id: '1003', title: 'Introduce this feature.' },
+				{ id: '1004', title: 'Missing docs.' },
+				{ id: '1005', title: 'Another bug.' },
+				{ id: '1006', title: 'More bugs' }
+			];
+
+			beforeEach( () => {
+				return createClassicTestEditor( {
+					feeds: [
+						{
+							marker: '@',
+							feed: issues,
+							itemRenderer: item => item.title
+						}
+					]
+				} );
+			} );
+
+			it( 'should show panel for matched marker', () => {
+				setData( model, '<paragraph>foo []</paragraph>' );
+
+				model.change( writer => {
+					writer.insertText( '@', doc.selection.getFirstPosition() );
+				} );
+
+				return waitForDebounce()
+					.then( () => {
+						expect( panelView.isVisible ).to.be.true;
+						expect( editor.model.markers.has( 'mention' ) ).to.be.true;
+						expect( listView.items ).to.have.length( 5 );
+					} );
+			} );
+
+			describe( 'keys', () => {
+				describe( 'on arrows', () => {
+					it( 'should cycle down on arrow down', () => {
+						setData( model, '<paragraph>foo []</paragraph>' );
+
+						model.change( writer => {
+							writer.insertText( '@', doc.selection.getFirstPosition() );
+						} );
+
+						return waitForDebounce()
+							.then( () => {
+								expectChildViewsIsOnState( [ true, false, false, false, false ] );
+
+								const keyEvtData = {
+									keyCode: keyCodes.arrowdown,
+									preventDefault: sinon.spy(),
+									stopPropagation: sinon.spy()
+								};
+
+								fireKeyDownEvent( keyEvtData );
+								expectChildViewsIsOnState( [ false, true, false, false, false ] );
+
+								fireKeyDownEvent( keyEvtData );
+								expectChildViewsIsOnState( [ false, false, true, false, false ] );
+
+								fireKeyDownEvent( keyEvtData );
+								expectChildViewsIsOnState( [ false, false, false, true, false ] );
+
+								fireKeyDownEvent( keyEvtData );
+								expectChildViewsIsOnState( [ false, false, false, false, true ] );
+
+								fireKeyDownEvent( keyEvtData );
+								expectChildViewsIsOnState( [ true, false, false, false, false ] );
+							} );
+					} );
+
+					it( 'should cycle up on arrow up', () => {
+						setData( model, '<paragraph>foo []</paragraph>' );
+
+						model.change( writer => {
+							writer.insertText( '@', doc.selection.getFirstPosition() );
+						} );
+
+						return waitForDebounce()
+							.then( () => {
+								expectChildViewsIsOnState( [ true, false, false, false, false ] );
+
+								const keyEvtData = {
+									keyCode: keyCodes.arrowup,
+									preventDefault: sinon.spy(),
+									stopPropagation: sinon.spy()
+								};
+
+								fireKeyDownEvent( keyEvtData );
+								expectChildViewsIsOnState( [ false, false, false, false, true ] );
+
+								fireKeyDownEvent( keyEvtData );
+								expectChildViewsIsOnState( [ false, false, false, true, false ] );
+
+								fireKeyDownEvent( keyEvtData );
+								expectChildViewsIsOnState( [ false, false, true, false, false ] );
+
+								fireKeyDownEvent( keyEvtData );
+								expectChildViewsIsOnState( [ false, true, false, false, false ] );
+
+								fireKeyDownEvent( keyEvtData );
+								expectChildViewsIsOnState( [ true, false, false, false, false ] );
+							} );
+					} );
+				} );
+
+				describe( 'on "execute" keys', () => {
+					testExecuteKey( 'enter', keyCodes.enter, issues );
+
+					testExecuteKey( 'tab', keyCodes.tab, issues );
+
+					testExecuteKey( 'space', keyCodes.space, issues );
+				} );
+			} );
+		} );
+
+		describe( 'custom list item (DOM Element)', () => {
 			const issues = [
 				{ id: '1002', title: 'Some bug in editor.' },
 				{ id: '1003', title: 'Introduce this feature.' },
@@ -1142,7 +1260,7 @@ describe( 'MentionUI', () => {
 
 					const commandOptions = spy.getCall( 0 ).args[ 0 ];
 
-					assertCommandOptions( commandOptions, '@', { id: '@Barney', text: 'Barney' } );
+					assertCommandOptions( commandOptions, '@', { id: '@Barney', text: '@Barney' } );
 
 					const start = model.createPositionAt( doc.getRoot().getChild( 0 ), 4 );
 					const expectedRange = model.createRange( start, start.getShiftedBy( 1 ) );