Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 19 additions & 4 deletions src/pageScanner/checks/is-video-detected.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,33 @@ export default {
}
}

// .ogg is the Ogg Vorbis audio extension, but the Ogg container can also carry
// Theora video, so it stays in videoExtensions. To avoid flagging ordinary Ogg
// Vorbis audio (e.g. the Gutenberg Audio block), only count a .ogg match as video
// when it isn't attached to an <audio> element or one of its <source> children.
const isInAudioContainer = tag === 'audio' || ( tag === 'source' &&
node.parentNode &&
node.parentNode.nodeName.toLowerCase() === 'audio' );

const srcLower = src.toLowerCase();
const dataLower = data.toLowerCase();

const matchesExtension = videoExtensions.some( ( ext ) => {
const srcLower = src.toLowerCase();
const dataLower = data.toLowerCase();
// Check if the extension is at the end of the string or followed by a query parameter
return (
const matches = (
( srcLower.endsWith( ext ) || srcLower.includes( ext + '?' ) ) ||
( dataLower.endsWith( ext ) || dataLower.includes( ext + '?' ) )
);

if ( matches && ext === '.ogg' && isInAudioContainer ) {
return false;
}

return matches;
} );

const matchesKeyword = videoKeywords.some( ( keyword ) =>
src.toLowerCase().includes( keyword )
srcLower.includes( keyword )
);

const matchesType = type.toLowerCase().startsWith( 'video/' );
Expand Down
30 changes: 30 additions & 0 deletions tests/jest/rules/videoElementPresent.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,16 @@ describe( 'video_present rule', () => {
html: '<video><source src="movie.MP4"></video>',
shouldPass: false,
},
{
name: 'detects .ogg file used as a native <video> element src',
html: '<video src="movie.ogg" controls></video>',
shouldPass: false,
},
{
name: 'detects .ogg source that is not inside an <audio> element',
html: '<source src="clip.ogg">',
shouldPass: false,
},

// Should not trigger violations
{
Expand Down Expand Up @@ -135,6 +145,26 @@ describe( 'video_present rule', () => {
html: '<audio controls><source src="sound.mp3" type="audio/mpeg"></audio>',
shouldPass: true,
},
{
// Direct/minimal case: the <audio> element itself has a .ogg src, exercising the
// `tag === 'audio'` path in is-video-detected.js without any wrapping markup.
name: 'does not detect a plain <audio> element with a .ogg src',
html: '<audio controls src="simple-guitar-melody.ogg"></audio>',
shouldPass: true,
},
{
// Regression test for https://github.com/equalizedigital/accessibility-checker/issues/1816 (PRO-1168).
// The Gutenberg Audio block's default sample audio is an .ogg (Ogg Vorbis) file, which was
// being misidentified as video content because .ogg is also a valid Ogg Theora video extension.
name: 'does not detect .ogg audio file in a <figure class="wp-block-audio"> Audio block',
html: '<figure class="wp-block-audio"><audio controls src="simple-guitar-melody.ogg"></audio><figcaption>Simple Guitar Melody</figcaption></figure>',
shouldPass: true,
},
{
name: 'does not detect .ogg source element inside an <audio> element',
html: '<audio controls><source src="simple-guitar-melody.ogg" type="audio/ogg"></audio>',
shouldPass: true,
},
{
name: 'does not detect YouTube API script tag',
html: '<script type="text/javascript" src="https://www.youtube.com/iframe_api?ver=1.2.6" id="youtube-scripts-js"></script>',
Expand Down
Loading