SearchPreview: Code improvement - Create a DOM modules to centralise all DOM manipulations

- Move all DOM actions into its own module
- Update unit tests

Bug: T339353
Change-Id: I2c23f4c7efb567b02dd75990572831fc04619c1a
这个提交包含在:
Simone Cuomo 2023-06-20 09:11:51 +01:00
父节点 e69a3c10d8
当前提交 f1d554d5af
找不到此签名对应的密钥
GPG 密钥 ID: C6B30ACE8D4CBD1D
共有 12 个文件被更改,包括 265 次插入139 次删除

查看文件

@ -58,8 +58,7 @@ module.exports = exports = {
'loading'
] ),
mapState( useDomStore, [
'firstFocusableElement',
'lastFocusableElement'
'searchResults'
] )
),
methods: $.extend( {},
@ -71,7 +70,9 @@ module.exports = exports = {
mapActions( useDomStore, [
'focusDialog',
'handleTabTrap',
'updateTabbableElements'
'updateTabbableElements',
'focusCurrentResult',
'generateAndInsertAriaButton'
] ),
mapActions( useEventStore, [ 'initEventLoggingSession' ] ),
{
@ -83,34 +84,15 @@ module.exports = exports = {
},
restoreQuickViewOnNavigation() {
if ( this.queryQuickViewTitle ) {
const currentElement = this.currentElement( this.queryQuickViewTitle );
this.toggleVisibily( {
title: this.queryQuickViewTitle,
element: currentElement
} );
this.toggleVisibily( this.queryQuickViewTitle );
}
},
getSearchResults() {
// eslint-disable-next-line no-jquery/no-global-selector
return $( '#mw-content-text .mw-search-result-ns-0' )
.not( '#mw-content-text .mw-search-interwiki-results .mw-search-result-ns-0' );
},
currentElement: function ( title ) {
return this.getSearchResults().find( `[data-prefixedtext="${title}"]` ).closest( 'li' )[ 0 ];
},
leaving() {
// Emit QuickView closing event only if QuickView is present in url
if ( this.queryQuickViewTitle ) {
this.onPageClose();
}
},
generateAndInsertAriaButton( container ) {
const ariaButton = document.createElement( 'BUTTON' );
ariaButton.type = 'button';
ariaButton.classList.add( 'quickView-aria-button' );
ariaButton.ariaLabel = this.$i18n( 'searchvue-aria-button' ).text();
container.insertBefore( ariaButton, null );
},
closeAndFocus( event ) {
if ( !this.title ) {
return;
@ -118,7 +100,7 @@ module.exports = exports = {
// event.detail will be equal to 0 if triggered by keyboard
if ( event.detail === 0 ) {
this.currentElement( this.title ).querySelector( '.quickView-aria-button' ).focus();
this.focusCurrentResult( this.title );
}
this.closeQuickView();
},
@ -128,9 +110,7 @@ module.exports = exports = {
if ( searchResultLink.hasAttribute( 'data-prefixedtext' ) ) {
event.stopPropagation();
const resultTitle = searchResultLink.getAttribute( 'data-prefixedtext' );
const currentElement = this.currentElement( resultTitle );
const payload = { title: resultTitle, element: currentElement };
this.toggleVisibily( payload );
this.toggleVisibily( resultTitle );
}
},
resultHasInfoToDisplay( prefixedText ) {
@ -171,11 +151,10 @@ module.exports = exports = {
},
mounted: function () {
const searchResults = this.getSearchResults();
for ( const searchResultLi of searchResults ) {
for ( const searchResultLi of this.searchResults ) {
const searchResult = searchResultLi.querySelector( '.mw-search-result-heading' );
// Search Result will ne undefined if an user would type in the searchbox quickly
// Search Result will be undefined if an user would type in the searchbox quickly
// before the results are fully mapped. Quite probably triggered by a BOT.
if ( !searchResult ) {
return;
@ -188,13 +167,13 @@ module.exports = exports = {
searchResultLi.dataset.prefixedtext = prefixedText;
const searchResultContainer = searchResult.parentElement;
this.generateAndInsertAriaButton( searchResultContainer );
this.generateAndInsertAriaButton( searchResultContainer, this.$i18n( 'searchvue-aria-button' ).text() );
}
}
const searchResultWithQuickView = searchResults.filter( function ( resultIndex ) {
return searchResults[ resultIndex ].classList.contains( 'searchresult-with-quickview' );
} );
const searchResultWithQuickView = this.searchResults.filter( function ( resultIndex ) {
return this.searchResults[ resultIndex ].classList.contains( 'searchresult-with-quickview' );
}.bind( this ) );
// Mouse click
searchResultWithQuickView.find( '.searchresult, .mw-search-result-data, .quickView-aria-button' )
.click( function ( event ) {

查看文件

@ -32,7 +32,8 @@ const QuickView = require( './sections/QuickView.vue' ),
onDocumentScroll = require( '../composables/onDocumentScroll.js' ),
onResizeObserver = require( '../composables/onResizeObserver.js' ),
onDocumentResize = require( '../composables/onDocumentResize.js' ),
useRootStore = require( '../stores/Root.js' );
useRootStore = require( '../stores/Root.js' ),
useDomStore = require( '../stores/Dom.js' );
// @vue/component
module.exports = exports = {
@ -43,8 +44,9 @@ module.exports = exports = {
'content-skeleton': ContentSkeleton
},
setup() {
const domStore = useDomStore();
const { scrollY } = onDocumentScroll();
const { elementWidth } = onResizeObserver( document.querySelector( '#bodyContent' ) );
const { elementWidth } = onResizeObserver( domStore.pageContainer );
const { width } = onDocumentResize();
return {
@ -55,8 +57,6 @@ module.exports = exports = {
},
data: function () {
return {
pageContainer: document.querySelector( '#bodyContent' ),
searchContainer: document.querySelector( '.searchresults' ),
pageScrolled: false
};
},
@ -140,6 +140,10 @@ module.exports = exports = {
mapState( useRootStore, [
'breakpoints',
'visible'
] ),
mapState( useDomStore, [
'pageContainer',
'searchContainer'
] )
),
methods: $.extend(

查看文件

@ -72,17 +72,7 @@ module.exports = exports = {
mapState( useRequestStatusStore, [
'loading'
] )
),
methods: $.extend( {
getSearchResults() {
// eslint-disable-next-line no-jquery/no-global-selector
return $( '#mw-content-text .mw-search-result-ns-0' )
.not( '#mw-content-text .mw-search-interwiki-results .mw-search-result-ns-0' );
},
currentElement: function ( title ) {
return this.getSearchResults().find( `[data-prefixedtext="${title}"]` ).closest( 'li' )[ 0 ];
}
} )
)
};
</script>

查看文件

@ -5,18 +5,32 @@ const Pinia = require( 'pinia' );
const useDomStore = Pinia.defineStore( 'dom', {
state: () => ( {
container: '.mw-search-quick-view',
focusableElements: null
focusableElements: null,
pageContainer: document.querySelector( '#bodyContent' ),
searchContainer: document.querySelector( '.searchresults' ),
// eslint-disable-next-line no-jquery/no-global-selector
searchResults: $( '#mw-content-text .mw-search-result-ns-0' )
.not( '#mw-content-text .mw-search-interwiki-results .mw-search-result-ns-0' )
} ),
getters: {
firstFocusableElement() {
if ( this.focusableElements && this.focusableElements.length > 0 ) {
return this.focusableElements[ 0 ];
firstFocusableElement( state ) {
if ( state.focusableElements && state.focusableElements.length > 0 ) {
return state.focusableElements[ 0 ];
}
},
lastFocusableElement() {
if ( this.focusableElements && this.focusableElements.length > 0 ) {
return this.focusableElements[ this.focusableElements.length - 1 ];
lastFocusableElement( state ) {
if ( state.focusableElements && state.focusableElements.length > 0 ) {
return state.focusableElements[ state.focusableElements.length - 1 ];
}
},
currentSelectedResults( state ) {
return ( title ) => {
if ( title ) {
// phpcs:disable Squiz.WhiteSpace.OperatorSpacing.NoSpaceBefore,Squiz.WhiteSpace.OperatorSpacing.NoSpaceAfter
return state.searchResults.find( `[data-prefixedtext="${title}"]` ).closest( 'li' )[ 0 ];
// phpcs:enable Squiz.WhiteSpace.OperatorSpacing.NoSpaceBefore,Squiz.WhiteSpace.OperatorSpacing.NoSpaceAfter
}
};
}
},
actions: {
@ -76,6 +90,59 @@ const useDomStore = Pinia.defineStore( 'dom', {
}
}
},
/**
* Handle the addition and removal of classes to the body and other element to define
* when the Search Preview is open. This classes are used to apply specific CSS properties.
*
* @param {string} title
*/
handleClassesToggle( title ) {
if ( title ) {
document.getElementsByTagName( 'body' )[ 0 ].classList.add( 'search-preview-open' );
this.currentSelectedResults( title ).classList.add( 'searchresult-with-quickview--open' );
} else {
document.getElementsByTagName( 'body' )[ 0 ].classList.remove( 'search-preview-open' );
const openElement = document.getElementsByClassName( 'searchresult-with-quickview--open' )[ 0 ];
if ( openElement ) {
openElement.classList.remove( 'searchresult-with-quickview--open' );
}
}
},
/**
* Moves the focus to the main search result element. This action is usually triggered after
* the search view container is closed using keyboard navigation.
*
* @param {string} title
*/
focusCurrentResult( title ) {
this.currentSelectedResults( title ).querySelector( '.quickView-aria-button' ).focus();
},
/**
* handled the modification of the main text snippets shown in the search result page.
*
* @param {string} title
* @param {string} snippet
* @param {boolean} isMobile
*/
updateMainSearchResultSnippets: ( title, snippet, isMobile ) => {
if ( !title || !snippet || !isMobile ) {
return;
}
const selector = '[data-prefixedtext="' + title + '"] .searchresult';
// Edge case in which the search result has no text within it (empty page)
if ( document.querySelector( selector ) ) {
document.querySelector( selector ).innerHTML = snippet;
}
},
generateAndInsertAriaButton( container, ariaLabel ) {
const ariaButton = document.createElement( 'BUTTON' );
ariaButton.type = 'button';
ariaButton.classList.add( 'quickView-aria-button' );
ariaButton.ariaLabel = ariaLabel;
container.insertBefore( ariaButton, null );
}
}
} );

查看文件

@ -3,6 +3,7 @@
const Pinia = require( 'pinia' );
const useRequestStatusStore = require( './RequestStatus.js' );
const useMediaStore = require( './Media.js' );
const useDomStore = require( './Dom.js' );
const restApi = new mw.Rest();
@ -239,26 +240,6 @@ const generateExpandedSnippet = ( page, currentResult, isMobile ) => {
};
};
/**
* handled the modification of the main text snippets shown in the search result page.
*
* @param {string} title
* @param {string} snippet
* @param {boolean} isMobile
*/
const updateMainSearchResultSnippets = ( title, snippet, isMobile ) => {
if ( !title || !snippet || !isMobile ) {
return;
}
const selector = '[data-prefixedtext="' + title + '"] .searchresult';
// Edge case in which the search result has no text within it (empty page)
if ( document.querySelector( selector ) ) {
document.querySelector( selector ).innerHTML = snippet;
}
};
/**
* Restore the main text snippets to its original value.
*
@ -269,9 +250,10 @@ const restoreMainSearchResultSnippets = ( currentResult, isMobile ) => {
if ( !currentResult ) {
return;
}
const domStore = useDomStore();
// The original snippet does not have ellipsis at the end of it
const snippet = currentResult.text + mw.msg( 'ellipsis' );
updateMainSearchResultSnippets( currentResult.prefixedText, snippet, isMobile );
domStore.updateMainSearchResultSnippets( currentResult.prefixedText, snippet, isMobile );
};
/**
@ -356,6 +338,7 @@ const useQueryStore = Pinia.defineStore( 'query', {
const requestStatusStore = useRequestStatusStore();
const mediaStore = useMediaStore();
const domStore = useDomStore();
requestStatusStore.setRequestStatus( {
type: 'query',
status: requestStatusStore.requestStatuses.inProgress
@ -384,7 +367,7 @@ const useQueryStore = Pinia.defineStore( 'query', {
mediaStore.setMediaInfo( result, isMobile );
const sections = getArticleSections( result );
const snippetObject = generateExpandedSnippet( result, currentSelectedResult, isMobile );
updateMainSearchResultSnippets( title, snippetObject.expandedSnippet, isMobile );
domStore.updateMainSearchResultSnippets( title, snippetObject.expandedSnippet, isMobile );
const description = getDescription( result, snippetObject.isBeginningOfText, isMobile );
this.$patch( {

查看文件

@ -4,6 +4,7 @@ const Pinia = require( 'pinia' );
const useEventStore = require( './Event.js' );
const useQueryStore = require( './Query.js' );
const useMediaStore = require( './Media.js' );
const useDomStore = require( './Dom.js' );
const useRequestStatusStore = require( './RequestStatus.js' );
/**
@ -42,26 +43,6 @@ const removeQuickViewFromHistoryState = () => {
window.history.pushState( mwUri.query, null, queryString );
};
/**
* Handle the addition and removal of classes to the body and other element to define
* when the Search Preview is open. This classes are used to apply specific CSS properties.
*
* @param {boolean} open
* @param {Element} currentElement
*/
const handleClassesToggle = ( open, currentElement ) => {
if ( open ) {
document.getElementsByTagName( 'body' )[ 0 ].classList.add( 'search-preview-open' );
currentElement.classList.add( 'searchresult-with-quickview--open' );
} else {
document.getElementsByTagName( 'body' )[ 0 ].classList.remove( 'search-preview-open' );
const openElement = document.getElementsByClassName( 'searchresult-with-quickview--open' )[ 0 ];
if ( openElement ) {
openElement.classList.remove( 'searchresult-with-quickview--open' );
}
}
};
const useRootStore = Pinia.defineStore( 'root', {
state: () => ( {
title: null,
@ -144,11 +125,9 @@ const useRootStore = Pinia.defineStore( 'root', {
/**
* Handles the visibility of the Search Preview definiting title.
*
* @param {Object} payload
* @param {string} payload.title
* @param {Element} payload.element
* @param {string} title
*/
toggleVisibily( { title, element } ) {
toggleVisibily( title ) {
let destination = '.searchresults';
if ( this.isMobile ) {
// phpcs:disable Squiz.WhiteSpace.OperatorSpacing.NoSpaceBefore,Squiz.WhiteSpace.OperatorSpacing.NoSpaceAfter
@ -158,17 +137,15 @@ const useRootStore = Pinia.defineStore( 'root', {
}
this.destination = destination;
this.handleTitleChange( { newTitle: title, element: element } );
this.handleTitleChange( title );
},
/**
* Handle the change in title by retrieving the information from server
* and managing the visibility of the panel
*
* @param {Object} payload
* @param {?string} payload.newTitle
* @param {?Element} payload.element
* @param {?string} newTitle
*/
handleTitleChange( { newTitle: newTitle, element: element } ) {
handleTitleChange( newTitle ) {
if ( !newTitle ) {
return;
}
@ -176,6 +153,7 @@ const useRootStore = Pinia.defineStore( 'root', {
const currentTitle = this.title;
const eventStore = useEventStore();
const queryStore = useQueryStore();
const domStore = useDomStore();
// This invokes on each title change
this.closeQuickView();
@ -192,7 +170,7 @@ const useRootStore = Pinia.defineStore( 'root', {
queryStore.retrieveInfoFromQuery( newTitle, selectedTitleIndex, this.results, this.isMobile );
this.title = newTitle;
pushTitleToHistoryState( newTitle );
handleClassesToggle( true, element );
domStore.handleClassesToggle( newTitle );
this.selectedIndex = selectedTitleIndex;
@ -206,6 +184,7 @@ const useRootStore = Pinia.defineStore( 'root', {
const mediaStore = useMediaStore();
const queryStore = useQueryStore();
const domStore = useDomStore();
const requestStatusStore = useRequestStatusStore();
if ( this.title !== null ) {
@ -225,7 +204,7 @@ const useRootStore = Pinia.defineStore( 'root', {
mediaStore.abort();
queryStore.abort();
mediaStore.$reset();
handleClassesToggle( false );
domStore.handleClassesToggle();
},
/**
* Emit close event when page is closing/refreshing while QuickView is open

查看文件

@ -0,0 +1,5 @@
const mockElement = require( './element.js' );
document.querySelector = jest.fn().mockImplementation( () => mockElement );
document.getElementsByTagName = jest.fn().mockImplementation( () => [ mockElement ] );
document.getElementsByClassName = jest.fn().mockImplementation( () => [ mockElement ] );

查看文件

@ -1,6 +1,9 @@
module.exports = {
innerHTML: 'dummyElement',
querySelectorAll: jest.fn(),
classList: {
add: jest.fn(),
remove: jest.fn()
}
},
focus: jest.fn()
};

查看文件

@ -1,6 +0,0 @@
document.querySelector = jest.fn().mockImplementation( () => {
return {
innerHTML: '',
querySelectorAll: jest.fn()
};
} );

查看文件

@ -1,16 +1,37 @@
const useDomStore = require( '../../../resources/stores/Dom.js' ),
Pinia = require( 'pinia' );
require( '../mocks/querySelector.js' );
Pinia = require( 'pinia' ),
mockElement = require( '../mocks/element.js' );
require( '../mocks/domSelector.js' );
beforeEach( () => {
Pinia.setActivePinia( Pinia.createPinia() );
} );
const createMockElement = ( name ) => {
const fakeElement = document.createElement( 'div' );
fakeElement.textContent = name;
fakeElement.focus = jest.fn();
return fakeElement;
};
describe( 'Dom store', () => {
let domStore;
beforeEach( () => {
domStore = useDomStore();
domStore.searchResults = {
find: jest.fn().mockReturnValueOnce( {
closest: jest.fn().mockReturnValueOnce( [
Object.assign(
{
// We cannot add this directly in the MockElement otherwise it will trigger a circular dependencies
querySelector: document.querySelector
},
mockElement
)
] )
} )
};
} );
describe( 'Getters', () => {
describe( 'firstFocusableElement', () => {
@ -38,6 +59,14 @@ describe( 'Dom store', () => {
expect( domStore.lastFocusableElement ).toEqual( 'third' );
} );
} );
describe( 'currentSelectedResults', () => {
it( 'Return null if no title is passed', () => {
expect( domStore.currentSelectedResults() ).toBeFalsy();
} );
it( 'Return the result element if a title is passed', () => {
expect( domStore.currentSelectedResults( 'dummy' ).innerHTML ).toEqual( 'dummyElement' );
} );
} );
} );
describe( 'Actions', () => {
describe( 'updateTabbableElements', () => {
@ -75,13 +104,6 @@ describe( 'Dom store', () => {
describe( 'handleTabTrap', () => {
let mockEvent;
beforeEach( () => {
const createMockElement = ( name ) => {
const fakeElement = document.createElement( 'div' );
fakeElement.textContent = name;
fakeElement.focus = jest.fn();
return fakeElement;
};
domStore.focusableElements = [
createMockElement( 'firstElement' ),
createMockElement( 'secondElement' )
@ -125,5 +147,102 @@ describe( 'Dom store', () => {
expect( mockEvent.preventDefault ).toHaveBeenCalled();
} );
} );
describe( 'handleClassesToggle', () => {
describe( 'When no title is passed', () => {
it( 'remove class "search-preview-open" from body', () => {
domStore.handleClassesToggle();
expect( document.getElementsByTagName ).toHaveBeenCalled();
expect( mockElement.classList.remove ).toHaveBeenCalledWith( 'search-preview-open' );
} );
it( 'remove class "searchresult-with-quickview--open" from search result', () => {
// We mock the currentSelectedResult getter
domStore.currentSelectedResults = mockElement;
domStore.handleClassesToggle();
expect( document.getElementsByClassName ).toHaveBeenCalled();
expect( mockElement.classList.remove ).toHaveBeenCalledWith( 'searchresult-with-quickview--open' );
} );
} );
describe( 'When title is passed', () => {
it( 'add class "search-preview-open" from body', () => {
domStore.handleClassesToggle( 'dummy' );
expect( document.getElementsByTagName ).toHaveBeenCalled();
expect( mockElement.classList.add ).toHaveBeenCalledWith( 'search-preview-open' );
} );
it( 'add class "searchresult-with-quickview--open" from search result', () => {
domStore.handleClassesToggle( 'dummy' );
expect( mockElement.classList.add ).toHaveBeenCalledWith( 'searchresult-with-quickview--open' );
} );
} );
} );
describe( 'focusCurrentResult', () => {
it( 'Calls focus on the current element', () => {
domStore.focusCurrentResult( 'dummy' );
expect( mockElement.focus ).toHaveBeenCalled();
} );
} );
describe( 'updateMainSearchResultSnippets', () => {
beforeEach( () => {
} );
describe( 'does not update dom when the following argument is missing', () => {
it( 'title', () => {
domStore.updateMainSearchResultSnippets( false, 'dummySnippet', true );
expect( document.querySelector ).not.toHaveBeenCalledWith( expect.stringContaining( 'data-prefixedtext' ) );
} );
it( 'snippet', () => {
domStore.updateMainSearchResultSnippets( 'dummyTitle', undefined, true );
expect( document.querySelector ).not.toHaveBeenCalledWith( expect.stringContaining( 'data-prefixedtext' ) );
} );
it( 'isMobile', () => {
domStore.updateMainSearchResultSnippets( 'dummyTitle', 'dummySnippet' );
expect( document.querySelector ).not.toHaveBeenCalledWith( expect.stringContaining( 'data-prefixedtext' ) );
} );
} );
describe( 'when all paramethers are passed correctly', () => {
it( 'update the element with the provided snippet', () => {
const dummyElement = createMockElement( 'dummyElement' );
document.querySelector.mockReturnValue( dummyElement );
domStore.updateMainSearchResultSnippets( 'dummyTitle', 'dummySnippet', true );
expect( document.querySelector ).toHaveBeenCalledWith( expect.stringContaining( 'data-prefixedtext' ) );
expect( dummyElement.innerHTML ).toEqual( 'dummySnippet' );
} );
} );
} );
describe( 'generateAndInsertAriaButton', () => {
let container;
let insertBefore;
beforeEach( () => {
insertBefore = jest.fn();
container = {
insertBefore: insertBefore
};
} );
it( 'Attach a button to the provided container', () => {
domStore.generateAndInsertAriaButton( container );
expect( insertBefore ).toHaveBeenCalled();
// we check the first argument that should be the button itself
expect( insertBefore.mock.calls[ 0 ][ 0 ] ).toBeTruthy();
expect( insertBefore.mock.calls[ 0 ][ 0 ].type ).toBe( 'button' );
} );
it( 'Set the button aria label', () => {
const dummyAriaLabel = 'dummyAriaLabel';
domStore.generateAndInsertAriaButton( container, dummyAriaLabel );
expect( insertBefore ).toHaveBeenCalled();
// we check the first argument that should be the button itself
expect( insertBefore.mock.calls[ 0 ][ 0 ] ).toBeTruthy();
expect( insertBefore.mock.calls[ 0 ][ 0 ].ariaLabel ).toBe( dummyAriaLabel );
} );
} );
} );
} );

查看文件

@ -3,7 +3,7 @@ const useStore = require( '../../../resources/stores/Query.js' ),
when = require( 'jest-when' ).when,
useRequestStatusStore = require( '../../../resources/stores/RequestStatus.js' );
require( '../mocks/querySelector.js' );
require( '../mocks/domSelector.js' );
/**
* Quick little helper function to escape contents for use in regular expressions;

查看文件

@ -1,9 +1,9 @@
const useStore = require( '../../../resources/stores/Root.js' ),
Pinia = require( 'pinia' ),
fakeElement = require( '../mocks/element.js' ),
useMediaStore = require( '../../../resources/stores/Media.js' ),
useQueryStore = require( '../../../resources/stores/Query.js' ),
useEventStore = require( '../../../resources/stores/Event.js' );
useEventStore = require( '../../../resources/stores/Event.js' ),
useDomStore = require( '../../../resources/stores/Dom.js' );
require( '../mocks/history.js' );
beforeEach( () => {
@ -15,6 +15,7 @@ describe( 'Root store', () => {
let media;
let query;
let event;
let dom;
beforeEach( () => {
store = useStore();
} );
@ -130,14 +131,14 @@ describe( 'Root store', () => {
store.handleTitleChange = jest.fn();
} );
it( 'Set destination to false, if title is not passed', () => {
store.toggleVisibily( {} );
store.toggleVisibily();
expect( store.destination ).toBeFalsy();
} );
it( 'Set destination to title provided', () => {
const title = 'dummy';
store.toggleVisibily( { title: title } );
store.toggleVisibily( title );
expect( store.destination ).toContain( title );
} );
} );
@ -164,15 +165,17 @@ describe( 'Root store', () => {
query = useQueryStore();
media = useMediaStore();
event = useEventStore();
dom = useDomStore();
store.results = [
{ prefixedText: 'dummy1', thumbnail: { width: 1, height: 2 } },
{ prefixedText: 'dummy2' }
];
store.closeQuickView = jest.fn();
dom.handleClassesToggle = jest.fn();
} );
describe( 'when called with empty title', () => {
it( 'Nothing is committed', () => {
store.handleTitleChange( {} );
store.handleTitleChange();
expect( store.closeQuickView ).not.toHaveBeenCalled();
@ -183,7 +186,7 @@ describe( 'Root store', () => {
const title = 'dummy';
store.title = title;
store.closeQuickView = jest.fn();
store.handleTitleChange( { newTitle: title } );
store.handleTitleChange( title );
expect( store.closeQuickView ).toHaveBeenCalled();
@ -194,7 +197,7 @@ describe( 'Root store', () => {
it( 'Setup article thumbnail height and width from the info available in the result', () => {
const title = 'dummy1';
store.handleTitleChange( { newTitle: title, element: fakeElement } );
store.handleTitleChange( title );
expect( query.thumbnail ).toEqual( store.results[ 0 ].thumbnail );
@ -203,21 +206,21 @@ describe( 'Root store', () => {
query.retrieveInfoFromQuery = jest.fn();
const title = 'dummy1';
store.handleTitleChange( { newTitle: title, element: fakeElement } );
store.handleTitleChange( title );
expect( query.retrieveInfoFromQuery ).toHaveBeenCalled();
} );
it( 'and current title had no value, update the title', () => {
const title = 'dummy1';
store.handleTitleChange( { newTitle: title, element: fakeElement } );
store.handleTitleChange( title );
expect( store.title ).toEqual( title );
} );
it( 'and value differs from existing title, update the title', () => {
const title = 'dummy1';
store.handleTitleChange( { newTitle: title, element: fakeElement } );
store.handleTitleChange( title );
expect( store.title ).toEqual( title );
@ -225,7 +228,7 @@ describe( 'Root store', () => {
it( 'Adds QuickView to history state', () => {
const title = 'dummy1';
store.handleTitleChange( { newTitle: title, element: fakeElement } );
store.handleTitleChange( title );
expect( window.history.pushState ).toHaveBeenCalled();
expect( window.history.pushState ).toHaveBeenCalledWith(
@ -243,7 +246,7 @@ describe( 'Root store', () => {
const title = 'dummy2';
const eventName = 'open-searchpreview';
store.handleTitleChange( { newTitle: title, element: fakeElement } );
store.handleTitleChange( title );
expect( event.logQuickViewEvent.mock.calls[ 0 ][ 0 ].action ).toBe( eventName );
} );
} );