fix(immoscout): map exclusioncriteria swapflat to mobile API value swap_flat (#332)

The web UI encodes the 'no swap flats' filter as exclusioncriteria=swapflat,
but the mobile API only accepts swap_flat. Unknown values are not ignored by
the API - the whole search silently returns 0 results, so any saved search
with this filter never finds a single listing.

Map the value during web-to-mobile conversion and leave all other
exclusioncriteria values (e.g. projectlisting, which both APIs share)
untouched.
This commit is contained in:
Michel
2026-06-10 16:43:12 +02:00
committed by GitHub
parent 359e00e69f
commit 7a2dacaa61
2 changed files with 34 additions and 1 deletions

View File

@@ -103,6 +103,13 @@ const EQUIPMENT_MAP = {
lodgerflat: 'lodgerflat',
};
// The web UI uses "swapflat", but the mobile API only understands "swap_flat".
// An unknown value is not ignored: the API silently returns 0 results for the
// whole search. Other values (e.g. "projectlisting") are identical on both APIs.
const EXCLUSION_CRITERIA_MAP = {
swapflat: 'swap_flat',
};
const REAL_ESTATE_TYPE = {
'haus-mieten': 'houserent',
'wohnung-mieten': 'apartmentrent',
@@ -251,6 +258,9 @@ export function convertWebToMobile(webUrl) {
...(currentEquipmentParams ?? []),
...items.map((item) => EQUIPMENT_MAP[item.toLowerCase()]).filter(Boolean),
];
} else if (key === 'exclusioncriteria') {
const items = [].concat(val).flatMap((v) => `${v}`.split(','));
mobileParams[PARAM_NAME_MAP[key]] = items.map((item) => EXCLUSION_CRITERIA_MAP[item.toLowerCase()] ?? item);
} else {
mobileParams[PARAM_NAME_MAP[key]] = val;
}

View File

@@ -31,12 +31,35 @@ describe('#immoscout-mobile URL conversion', () => {
const webUrl =
'https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten?heatingtypes=central,selfcontainedcentral&haspromotion=false&numberofrooms=2.0-5.0&livingspace=10.0-25.0&energyefficiencyclasses=a,b,c,d,e,f,g,h,a_plus&exclusioncriteria=projectlisting,swapflat&equipment=parking,cellar,builtinkitchen,lift,garden,guesttoilet,balcony&petsallowedtypes=no,yes,negotiable&price=10.0-100.0&constructionyear=1920-2026&apartmenttypes=halfbasement,penthouse,other,loft,groundfloor,terracedflat,raisedgroundfloor,roofstorey,apartment,maisonette&pricetype=calculatedtotalrent&floor=2-7&enteredFrom=result_list';
const expectedMobileUrl =
'https://api.mobile.immobilienscout24.de/search/list?apartmenttypes=halfbasement,penthouse,other,loft,groundfloor,terracedflat,raisedgroundfloor,roofstorey,apartment,maisonette&constructionyear=1920-2026&energyefficiencyclasses=a,b,c,d,e,f,g,h,a_plus&equipment=parking,cellar,builtInKitchen,lift,garden,guestToilet,balcony&exclusioncriteria=projectlisting,swapflat&floor=2-7&geocodes=%2Fde%2Fberlin%2Fberlin&haspromotion=false&heatingtypes=central,selfcontainedcentral&livingspace=10.0-25.0&numberofrooms=2.0-5.0&petsallowedtypes=no,yes,negotiable&price=10.0-100.0&pricetype=calculatedtotalrent&realestatetype=apartmentrent&searchType=region';
'https://api.mobile.immobilienscout24.de/search/list?apartmenttypes=halfbasement,penthouse,other,loft,groundfloor,terracedflat,raisedgroundfloor,roofstorey,apartment,maisonette&constructionyear=1920-2026&energyefficiencyclasses=a,b,c,d,e,f,g,h,a_plus&equipment=parking,cellar,builtInKitchen,lift,garden,guestToilet,balcony&exclusioncriteria=projectlisting,swap_flat&floor=2-7&geocodes=%2Fde%2Fberlin%2Fberlin&haspromotion=false&heatingtypes=central,selfcontainedcentral&livingspace=10.0-25.0&numberofrooms=2.0-5.0&petsallowedtypes=no,yes,negotiable&price=10.0-100.0&pricetype=calculatedtotalrent&realestatetype=apartmentrent&searchType=region';
const actualMobileUrl = convertWebToMobile(webUrl);
expect(actualMobileUrl).toBe(expectedMobileUrl);
});
// The web UI encodes "no swap flats" as exclusioncriteria=swapflat, but the
// mobile API only understands swap_flat. Unknown values are not ignored by the
// API - the search silently returns 0 results, so the mapping is essential.
it('should map exclusioncriteria=swapflat to the mobile API value swap_flat', () => {
const webUrl =
'https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten?exclusioncriteria=swapflat&price=-1500.0';
const converted = convertWebToMobile(webUrl);
const queryParams = new URL(converted).searchParams;
expect(queryParams.get('exclusioncriteria')).toBe('swap_flat');
});
// Values the mobile API shares with the web API (e.g. projectlisting) must
// pass through unchanged, in any combination with mapped values.
it('should keep other exclusioncriteria values untouched', () => {
const webUrl =
'https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mieten?exclusioncriteria=projectlisting,swapflat';
const converted = convertWebToMobile(webUrl);
const queryParams = new URL(converted).searchParams;
expect(queryParams.get('exclusioncriteria')).toBe('projectlisting,swap_flat');
});
// Test URL conversion of web-only SEO path
it('should convert a SEO web path to the correct query params', () => {
const webUrl = 'https://www.immobilienscout24.de/Suche/de/berlin/berlin/wohnung-mit-balkon-mieten?equipment=garden';