@@ -38,6 +38,7 @@ import {
3838 DeleteProductMutationVariables ,
3939 DeleteProductVariantMutation ,
4040 DeleteProductVariantMutationVariables ,
41+ GlobalFlag ,
4142 LanguageCode ,
4243 ReindexMutation ,
4344 RemoveProductsFromChannelMutation ,
@@ -1941,6 +1942,134 @@ describe('Default search plugin', () => {
19411942 } ) ;
19421943 } ) ;
19431944 } ) ;
1945+
1946+ // https://github.com/vendurehq/community-plugins/issues/1
1947+ describe ( 'multi-channel productInStock cache' , ( ) => {
1948+ const STOCK_CHANNEL_TOKEN = 'stock-test-channel-token' ;
1949+ let stockTestChannelId : string ;
1950+ let testProductId : string ;
1951+
1952+ beforeAll ( async ( ) => {
1953+ adminClient . setChannelToken ( E2E_DEFAULT_CHANNEL_TOKEN ) ;
1954+ await adminClient . asSuperAdmin ( ) ;
1955+
1956+ // Create a second channel for testing stock isolation
1957+ const { createChannel } = await adminClient . query <
1958+ CreateChannelMutation ,
1959+ CreateChannelMutationVariables
1960+ > ( CREATE_CHANNEL , {
1961+ input : {
1962+ code : 'stock-test-channel' ,
1963+ token : STOCK_CHANNEL_TOKEN ,
1964+ defaultLanguageCode : LanguageCode . en ,
1965+ currencyCode : CurrencyCode . GBP ,
1966+ pricesIncludeTax : true ,
1967+ defaultTaxZoneId : 'T_2' ,
1968+ defaultShippingZoneId : 'T_1' ,
1969+ } ,
1970+ } ) ;
1971+ stockTestChannelId = ( createChannel as ChannelFragment ) . id ;
1972+
1973+ // Create a product with a variant that has stock in the default channel
1974+ const { createProduct } = await adminClient . query <
1975+ CreateProductMutation ,
1976+ CreateProductMutationVariables
1977+ > ( CREATE_PRODUCT , {
1978+ input : {
1979+ translations : [
1980+ {
1981+ languageCode : LanguageCode . en ,
1982+ name : 'Stock Test Product' ,
1983+ slug : 'stock-test-product' ,
1984+ description : 'A product for testing multi-channel stock' ,
1985+ } ,
1986+ ] ,
1987+ } ,
1988+ } ) ;
1989+ testProductId = createProduct . id ;
1990+
1991+ await adminClient . query < CreateProductVariantsMutation , CreateProductVariantsMutationVariables > (
1992+ CREATE_PRODUCT_VARIANTS ,
1993+ {
1994+ input : [
1995+ {
1996+ productId : testProductId ,
1997+ sku : 'STOCK-TEST-1' ,
1998+ price : 1000 ,
1999+ stockOnHand : 100 ,
2000+ trackInventory : GlobalFlag . TRUE ,
2001+ translations : [ { languageCode : LanguageCode . en , name : 'Stock Test Variant' } ] ,
2002+ } ,
2003+ ] ,
2004+ } ,
2005+ ) ;
2006+ await awaitRunningJobs ( adminClient ) ;
2007+
2008+ // Assign the product to the second channel (no stock location there)
2009+ await adminClient . query <
2010+ AssignProductsToChannelMutation ,
2011+ AssignProductsToChannelMutationVariables
2012+ > ( ASSIGN_PRODUCT_TO_CHANNEL , {
2013+ input : { channelId : stockTestChannelId , productIds : [ testProductId ] } ,
2014+ } ) ;
2015+ await awaitRunningJobs ( adminClient ) ;
2016+
2017+ // Reindex default channel first
2018+ adminClient . setChannelToken ( E2E_DEFAULT_CHANNEL_TOKEN ) ;
2019+ await adminClient . query < ReindexMutation > ( REINDEX ) ;
2020+ await awaitRunningJobs ( adminClient ) ;
2021+
2022+ // Reindex the second channel
2023+ adminClient . setChannelToken ( STOCK_CHANNEL_TOKEN ) ;
2024+ await adminClient . query < ReindexMutation > ( REINDEX ) ;
2025+ await awaitRunningJobs ( adminClient ) ;
2026+ } ) ;
2027+
2028+ it ( 'product is inStock in default channel' , async ( ) => {
2029+ shopClient . setChannelToken ( E2E_DEFAULT_CHANNEL_TOKEN ) ;
2030+ const result = await shopClient . query <
2031+ SearchProductsShopQuery ,
2032+ SearchProductsShopQueryVariablesExt
2033+ > ( SEARCH_PRODUCTS_SHOP , {
2034+ input : {
2035+ term : 'Stock Test Product' ,
2036+ groupByProduct : true ,
2037+ inStock : true ,
2038+ } ,
2039+ } ) ;
2040+ expect ( result . search . items . map ( i => i . productName ) ) . toContain ( 'Stock Test Product' ) ;
2041+ } ) ;
2042+
2043+ it ( 'product is NOT inStock in second channel (no stock location)' , async ( ) => {
2044+ shopClient . setChannelToken ( STOCK_CHANNEL_TOKEN ) ;
2045+ const result = await shopClient . query <
2046+ SearchProductsShopQuery ,
2047+ SearchProductsShopQueryVariablesExt
2048+ > ( SEARCH_PRODUCTS_SHOP , {
2049+ input : {
2050+ term : 'Stock Test Product' ,
2051+ groupByProduct : true ,
2052+ inStock : true ,
2053+ } ,
2054+ } ) ;
2055+ expect ( result . search . items . map ( i => i . productName ) ) . not . toContain ( 'Stock Test Product' ) ;
2056+ } ) ;
2057+
2058+ it ( 'product appears when filtering inStock: false in second channel' , async ( ) => {
2059+ shopClient . setChannelToken ( STOCK_CHANNEL_TOKEN ) ;
2060+ const result = await shopClient . query <
2061+ SearchProductsShopQuery ,
2062+ SearchProductsShopQueryVariablesExt
2063+ > ( SEARCH_PRODUCTS_SHOP , {
2064+ input : {
2065+ term : 'Stock Test Product' ,
2066+ groupByProduct : true ,
2067+ inStock : false ,
2068+ } ,
2069+ } ) ;
2070+ expect ( result . search . items . map ( i => i . productName ) ) . toContain ( 'Stock Test Product' ) ;
2071+ } ) ;
2072+ } ) ;
19442073} ) ;
19452074
19462075export const REINDEX = gql `
0 commit comments