@@ -19,6 +19,9 @@ type FakeNode = {
1919 querySelector : ( selector : string ) => FakeNode | null ;
2020 setAttribute : ( name : string , value : string ) => void ;
2121 attributes : Record < string , string > ;
22+ value ?: string ;
23+ listeners : Record < string , ( ) => void > ;
24+ addEventListener : ( type : string , handler : ( ) => void ) => void ;
2225} ;
2326
2427/**
@@ -40,6 +43,8 @@ function node( tagName?: string ): FakeNode {
4043 querySelector : ( ) => null ,
4144 attributes : { } ,
4245 setAttribute : ( name , value ) => void ( el . attributes [ name ] = value ) ,
46+ listeners : { } ,
47+ addEventListener : ( type , handler ) => void ( el . listeners [ type ] = handler ) ,
4348 } ;
4449 return el ;
4550}
@@ -430,3 +435,75 @@ it( 'stops marking a theme once it renders outside the tab', () => {
430435 ) ;
431436 assert . equal ( page . activate ( 'click' , 'organic-stax' ) , null ) ;
432437} ) ;
438+
439+ /**
440+ * Loads the script on a page with core's filter bar and theme collection.
441+ *
442+ * @return The pricing filter, and what core's collection and installer were asked for.
443+ */
444+ function pricingPage ( ) {
445+ const list = node ( 'ul' ) ;
446+ const requests : unknown [ ] = [ ] ;
447+ const browsed : string [ ] = [ ] ;
448+ const Collection = {
449+ prototype : { query : ( request : unknown ) => void requests . push ( request ) } ,
450+ } ;
451+ const config = { sort : 'wpcom' , label : 'Marketplace' , included : 'included' } ;
452+ const context = {
453+ document : { querySelector : ( ) => list , createElement : node , addEventListener : ( ) => { } } ,
454+ window : {
455+ wpcomThemesTab : config ,
456+ wp : {
457+ themes : {
458+ view : { Theme : { prototype : { render : ( ) => undefined } } } ,
459+ Collection,
460+ RunInstaller : { view : { browse : ( section : string ) => void browsed . push ( section ) } } ,
461+ } ,
462+ } ,
463+ } ,
464+ wpcomThemesTab : config ,
465+ } ;
466+ const file = new URL ( './themes-tab.js' , import . meta. url ) . pathname ;
467+ vm . createContext ( context ) ;
468+ new vm . Script ( readFileSync ( file , 'utf8' ) , { filename : file } ) . runInContext ( context ) ;
469+
470+ const pricing = list . children . find ( child => child . className === 'wpcom-themes-tab__pricing' ) ;
471+ assert . ok ( pricing ) ;
472+
473+ return {
474+ pricing,
475+ select : pricing . children [ 1 ] ,
476+ query : ( request : Record < string , unknown > ) => Collection . prototype . query . call ( { } , request ) ,
477+ // The script builds some requests in the vm's realm, which a strict deepEqual tells apart.
478+ requests : ( ) => JSON . parse ( JSON . stringify ( requests ) ) ,
479+ browsed,
480+ } ;
481+ }
482+
483+ it ( "narrows the tab's query and its later pages, and nothing else, to what the plan includes" , ( ) => {
484+ const page = pricingPage ( ) ;
485+ page . query ( { browse : 'wpcom' } ) ;
486+ assert . equal ( page . pricing . hidden , false ) ;
487+
488+ page . select . value = 'included' ;
489+ page . query ( { browse : 'wpcom' } ) ;
490+ page . query ( { browse : 'wpcom' , wpcom_pricing : 'included' , page : 2 } ) ;
491+ page . query ( { browse : 'popular' } ) ;
492+ assert . equal ( page . pricing . hidden , true ) ;
493+ page . query ( { search : 'blog' } ) ;
494+
495+ assert . deepEqual ( page . requests ( ) , [
496+ { browse : 'wpcom' } ,
497+ { browse : 'wpcom' , wpcom_pricing : 'included' } ,
498+ { browse : 'wpcom' , wpcom_pricing : 'included' , page : 2 } ,
499+ { browse : 'popular' } ,
500+ { search : 'blog' } ,
501+ ] ) ;
502+ } ) ;
503+
504+ it ( 'lists the tab again when the filter changes' , ( ) => {
505+ const page = pricingPage ( ) ;
506+ page . select . listeners . change ( ) ;
507+
508+ assert . deepEqual ( page . browsed , [ 'wpcom' ] ) ;
509+ } ) ;
0 commit comments