mirror of
https://gerrit.wikimedia.org/r/mediawiki/skins/Vector.git
synced 2024-11-24 15:53:46 +00:00
Merge "Add Jest tests for TOC before/after edit"
This commit is contained in:
commit
b590555126
|
@ -29,10 +29,10 @@ module.exports = {
|
|||
// An object that configures minimum threshold enforcement for coverage results
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
branches: 14,
|
||||
functions: 24,
|
||||
lines: 22,
|
||||
statements: 22
|
||||
branches: 25,
|
||||
functions: 29,
|
||||
lines: 32,
|
||||
statements: 33
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -1,5 +1,82 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Table of contents re-rendering re-renders toc when wikipage.tableOfContents hook is fired with empty sections 1`] = `
|
||||
"<nav id=\\"mw-panel-toc\\" class=\\"sidebar-toc\\" role=\\"navigation\\" aria-labelledby=\\"sidebar-toc-label\\" data-event-name=\\"ui.sidebar-toc\\"></nav>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Table of contents re-rendering re-renders toc when wikipage.tableOfContents hook is fired with sections 1`] = `
|
||||
"<nav id=\\"mw-panel-toc\\" class=\\"sidebar-toc\\" role=\\"navigation\\" aria-labelledby=\\"sidebar-toc-label\\" data-event-name=\\"ui.sidebar-toc\\"><nav id=\\"mw-panel-toc\\" class=\\"sidebar-toc\\" role=\\"navigation\\" aria-labelledby=\\"sidebar-toc-label\\" data-event-name=\\"ui.sidebar-toc\\">
|
||||
<div id=\\"sidebar-toc-label\\" class=\\"sidebar-toc-header\\">
|
||||
<p class=\\"sidebar-toc-title\\">
|
||||
Contents
|
||||
<button class=\\"vector-toc-uncollapse-button\\">move to sidebar</button>
|
||||
<button class=\\"vector-toc-collapse-button\\">hide</button>
|
||||
</p>
|
||||
</div>
|
||||
<ul class=\\"sidebar-toc-contents\\" id=\\"mw-panel-toc-list\\">
|
||||
<li id=\\"toc-mw-content-text\\" class=\\"sidebar-toc-list-item sidebar-toc-level-1\\">
|
||||
<a href=\\"#top-page\\" class=\\"sidebar-toc-link\\">
|
||||
<div class=\\"sidebar-toc-text\\">Beginning</div>
|
||||
</a>
|
||||
</li>
|
||||
<li id=\\"toc-foo\\" class=\\"sidebar-toc-list-item sidebar-toc-level-1 sidebar-toc-list-item-expanded\\">
|
||||
<a class=\\"sidebar-toc-link\\" href=\\"#foo\\">
|
||||
<div class=\\"sidebar-toc-text\\">
|
||||
<span class=\\"sidebar-toc-numb\\">1</span>foo</div>
|
||||
</a>
|
||||
<ul id=\\"toc-foo-sublist\\" class=\\"sidebar-toc-list\\">
|
||||
</ul>
|
||||
</li>
|
||||
<li id=\\"toc-bar\\" class=\\"sidebar-toc-list-item sidebar-toc-level-1 sidebar-toc-list-item-expanded\\">
|
||||
<a class=\\"sidebar-toc-link\\" href=\\"#bar\\">
|
||||
<div class=\\"sidebar-toc-text\\">
|
||||
<span class=\\"sidebar-toc-numb\\">2</span>bar</div>
|
||||
</a>
|
||||
<button aria-controls=\\"toc-bar-sublist\\" class=\\"mw-ui-icon mw-ui-icon-wikimedia-expand mw-ui-icon-small sidebar-toc-toggle\\" aria-expanded=\\"true\\">
|
||||
Toggle bar subsection
|
||||
</button>
|
||||
<ul id=\\"toc-bar-sublist\\" class=\\"sidebar-toc-list\\">
|
||||
<li id=\\"toc-baz\\" class=\\"sidebar-toc-list-item sidebar-toc-level-2\\">
|
||||
<a class=\\"sidebar-toc-link\\" href=\\"#baz\\">
|
||||
<div class=\\"sidebar-toc-text\\">
|
||||
<span class=\\"sidebar-toc-numb\\">2.1</span>baz</div>
|
||||
</a>
|
||||
<ul id=\\"toc-baz-sublist\\" class=\\"sidebar-toc-list\\">
|
||||
<li id=\\"toc-qux\\" class=\\"sidebar-toc-list-item sidebar-toc-level-3\\">
|
||||
<a class=\\"sidebar-toc-link\\" href=\\"#qux\\">
|
||||
<div class=\\"sidebar-toc-text\\">
|
||||
<span class=\\"sidebar-toc-numb\\">2.1.1</span>qux</div>
|
||||
</a>
|
||||
<ul id=\\"toc-qux-sublist\\" class=\\"sidebar-toc-list\\">
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li id=\\"toc-quux\\" class=\\"sidebar-toc-list-item sidebar-toc-level-1 sidebar-toc-list-item-expanded\\">
|
||||
<a class=\\"sidebar-toc-link\\" href=\\"#quux\\">
|
||||
<div class=\\"sidebar-toc-text\\">
|
||||
<span class=\\"sidebar-toc-numb\\">3</span>quux</div>
|
||||
</a>
|
||||
<ul id=\\"toc-quux-sublist\\" class=\\"sidebar-toc-list\\">
|
||||
</ul>
|
||||
</li>
|
||||
<li id=\\"toc-bat\\" class=\\"sidebar-toc-list-item sidebar-toc-level-1 sidebar-toc-list-item-expanded\\">
|
||||
<a class=\\"sidebar-toc-link\\" href=\\"#bat\\">
|
||||
<div class=\\"sidebar-toc-text\\">
|
||||
<span class=\\"sidebar-toc-numb\\">4</span>bat</div>
|
||||
</a>
|
||||
<ul id=\\"toc-bat-sublist\\" class=\\"sidebar-toc-list\\">
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</nav>
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`Table of contents renders when \`vector-is-collapse-sections-enabled\` is false 1`] = `
|
||||
"<nav id=\\"mw-panel-toc\\" class=\\"sidebar-toc\\" role=\\"navigation\\" aria-labelledby=\\"sidebar-toc-label\\" data-event-name=\\"ui.sidebar-toc\\">
|
||||
<div id=\\"sidebar-toc-label\\" class=\\"sidebar-toc-header\\">
|
||||
|
|
|
@ -13,6 +13,51 @@ const onHeadingClick = jest.fn();
|
|||
const onToggleClick = jest.fn();
|
||||
const onToggleCollapse = jest.fn();
|
||||
|
||||
const SECTIONS = [
|
||||
{
|
||||
toclevel: 1,
|
||||
number: '1',
|
||||
line: 'foo',
|
||||
anchor: 'foo',
|
||||
'is-top-level-section': true,
|
||||
'is-parent-section': false,
|
||||
'array-sections': null
|
||||
}, {
|
||||
toclevel: 1,
|
||||
number: '2',
|
||||
line: 'bar',
|
||||
anchor: 'bar',
|
||||
'is-top-level-section': true,
|
||||
'is-parent-section': true,
|
||||
'vector-button-label': 'Toggle bar subsection',
|
||||
'array-sections': [ {
|
||||
toclevel: 2,
|
||||
number: '2.1',
|
||||
line: 'baz',
|
||||
anchor: 'baz',
|
||||
'is-top-level-section': false,
|
||||
'is-parent-section': true,
|
||||
'array-sections': [ {
|
||||
toclevel: 3,
|
||||
number: '2.1.1',
|
||||
line: 'qux',
|
||||
anchor: 'qux',
|
||||
'is-top-level-section': false,
|
||||
'is-parent-section': false,
|
||||
'array-sections': null
|
||||
} ]
|
||||
} ]
|
||||
}, {
|
||||
toclevel: 1,
|
||||
number: '3',
|
||||
line: 'quux',
|
||||
anchor: 'quux',
|
||||
'is-top-level-section': true,
|
||||
'is-parent-section': false,
|
||||
'array-sections': null
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* @param {Object} templateProps
|
||||
* @return {string}
|
||||
|
@ -23,48 +68,7 @@ function render( templateProps = {} ) {
|
|||
'msg-vector-toc-beginning': 'Beginning',
|
||||
'msg-vector-toc-heading': 'Contents',
|
||||
'vector-is-collapse-sections-enabled': false,
|
||||
'array-sections': [ {
|
||||
toclevel: 1,
|
||||
number: '1',
|
||||
line: 'foo',
|
||||
anchor: 'foo',
|
||||
'is-top-level-section': true,
|
||||
'is-parent-section': false,
|
||||
'array-sections': null
|
||||
}, {
|
||||
toclevel: 1,
|
||||
number: '2',
|
||||
line: 'bar',
|
||||
anchor: 'bar',
|
||||
'is-top-level-section': true,
|
||||
'is-parent-section': true,
|
||||
'vector-button-label': 'Toggle bar subsection',
|
||||
'array-sections': [ {
|
||||
toclevel: 2,
|
||||
number: '2.1',
|
||||
line: 'baz',
|
||||
anchor: 'baz',
|
||||
'is-top-level-section': false,
|
||||
'is-parent-section': true,
|
||||
'array-sections': [ {
|
||||
toclevel: 3,
|
||||
number: '2.1.1',
|
||||
line: 'qux',
|
||||
anchor: 'qux',
|
||||
'is-top-level-section': false,
|
||||
'is-parent-section': false,
|
||||
'array-sections': null
|
||||
} ]
|
||||
} ]
|
||||
}, {
|
||||
toclevel: 1,
|
||||
number: '3',
|
||||
line: 'quux',
|
||||
anchor: 'quux',
|
||||
'is-top-level-section': true,
|
||||
'is-parent-section': false,
|
||||
'array-sections': null
|
||||
} ]
|
||||
'array-sections': SECTIONS
|
||||
}, templateProps );
|
||||
|
||||
return mustache.render( tableOfContentsTemplate, templateData, {
|
||||
|
@ -215,4 +219,142 @@ describe( 'Table of contents', () => {
|
|||
expect( toggleButton.getAttribute( 'aria-expanded' ) ).toEqual( 'true' );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 're-rendering', () => {
|
||||
const mockMwHook = () => {
|
||||
/** @type {Function} */
|
||||
let callback;
|
||||
// @ts-ignore
|
||||
jest.spyOn( mw, 'hook' ).mockImplementation( () => {
|
||||
|
||||
return {
|
||||
add: function ( fn ) {
|
||||
callback = fn;
|
||||
|
||||
return this;
|
||||
},
|
||||
fire: ( data ) => {
|
||||
if ( callback ) {
|
||||
callback( data );
|
||||
}
|
||||
}
|
||||
};
|
||||
} );
|
||||
};
|
||||
|
||||
afterEach( () => {
|
||||
jest.restoreAllMocks();
|
||||
} );
|
||||
|
||||
test( 'listens to wikipage.tableOfContents hook when mounted', () => {
|
||||
const spy = jest.spyOn( mw, 'hook' );
|
||||
mount();
|
||||
expect( spy ).toHaveBeenCalledWith( 'wikipage.tableOfContents' );
|
||||
} );
|
||||
|
||||
test( 're-renders toc when wikipage.tableOfContents hook is fired with empty sections', () => {
|
||||
mockMwHook();
|
||||
mount();
|
||||
|
||||
mw.hook( 'wikipage.tableOfContents' ).fire( [] );
|
||||
|
||||
expect( document.body.innerHTML ).toMatchSnapshot();
|
||||
} );
|
||||
|
||||
test( 're-renders toc when wikipage.tableOfContents hook is fired with sections', async () => {
|
||||
mockMwHook();
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line compat/compat
|
||||
jest.spyOn( mw.loader, 'using' ).mockImplementation( () => Promise.resolve() );
|
||||
// @ts-ignore
|
||||
mw.template.getCompiler = () => {};
|
||||
jest.spyOn( mw, 'message' ).mockImplementation( ( msg ) => {
|
||||
const msgFactory = ( /** @type {string} */ text ) => {
|
||||
return {
|
||||
parse: () => '',
|
||||
plain: () => '',
|
||||
escaped: () => '',
|
||||
exists: () => true,
|
||||
text: () => text
|
||||
};
|
||||
};
|
||||
switch ( msg ) {
|
||||
case 'vector-toc-heading':
|
||||
return msgFactory( 'Contents' );
|
||||
case 'vector-toc-toggle-position-sidebar':
|
||||
return msgFactory( 'move to sidebar' );
|
||||
case 'vector-toc-toggle-position-title':
|
||||
return msgFactory( 'hide' );
|
||||
case 'vector-toc-beginning':
|
||||
return msgFactory( 'Beginning' );
|
||||
default:
|
||||
return msgFactory( '' );
|
||||
}
|
||||
|
||||
} );
|
||||
// @ts-ignore
|
||||
jest.spyOn( mw.template, 'getCompiler' ).mockImplementation( () => {
|
||||
return {
|
||||
compile: () => {
|
||||
return {
|
||||
render: ( /** @type {Object} */ data ) => {
|
||||
return {
|
||||
html: () => {
|
||||
return render( data );
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
} );
|
||||
|
||||
const toc = mount();
|
||||
|
||||
const toggleButton = /** @type {HTMLElement} */ ( barSection.querySelector( `.${toc.TOGGLE_CLASS}` ) );
|
||||
// Collapse section.
|
||||
toc.toggleExpandSection( 'toc-bar' );
|
||||
expect( toggleButton.getAttribute( 'aria-expanded' ) ).toEqual( 'false' );
|
||||
|
||||
// wikipage.tableOfContents includes the nested sections in the top level
|
||||
// of the array.
|
||||
mw.hook( 'wikipage.tableOfContents' ).fire( [
|
||||
// foo
|
||||
SECTIONS[ 0 ],
|
||||
// bar
|
||||
SECTIONS[ 1 ],
|
||||
// baz
|
||||
// @ts-ignore
|
||||
SECTIONS[ 1 ][ 'array-sections' ][ 0 ],
|
||||
// qux
|
||||
// @ts-ignore
|
||||
SECTIONS[ 1 ][ 'array-sections' ][ 0 ][ 'array-sections' ][ 0 ],
|
||||
// quux
|
||||
SECTIONS[ 2 ],
|
||||
// Add new section to see how the re-render performs.
|
||||
{
|
||||
toclevel: 1,
|
||||
number: '4',
|
||||
line: 'bat',
|
||||
anchor: 'bat',
|
||||
'is-top-level-section': true,
|
||||
'is-parent-section': false,
|
||||
'array-sections': null
|
||||
}
|
||||
] );
|
||||
|
||||
// Wait until the mw.loader.using promise has resolved so that we can
|
||||
// check the DOM after it has been updated.
|
||||
// eslint-disable-next-line compat/compat
|
||||
await Promise.resolve();
|
||||
|
||||
const newToggleButton = /** @type {HTMLElement} */ ( document.querySelector( `#toc-bar .${toc.TOGGLE_CLASS}` ) );
|
||||
expect( newToggleButton ).not.toBeNull();
|
||||
// Check that the sections render in their expanded form.
|
||||
expect( newToggleButton.getAttribute( 'aria-expanded' ) ).toEqual( 'true' );
|
||||
|
||||
// Verify newly rendered TOC html matches the expected html.
|
||||
expect( document.body.innerHTML ).toMatchSnapshot();
|
||||
} );
|
||||
} );
|
||||
} );
|
||||
|
|
Loading…
Reference in a new issue