Skip to content

Commit

Permalink
Refactored the logic so that a country name can be passed in from the…
Browse files Browse the repository at this point in the history
… DB. we convert it to a country code so it can check against the user payload which has the country code

Added in a number of unit tests to cover the new logic including the country code converter
  • Loading branch information
charleycampbell committed Jan 23, 2025
1 parent f401054 commit e79a33b
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 20 deletions.
64 changes: 64 additions & 0 deletions src/server/tests/epics/epicSelection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,70 @@ describe('matchesCountryGroups filter', () => {

expect(got).toBe(false);
});

it('should pass if user is in country group or targeted country', () => {
const test: EpicTest = {
...testDefault,
locations: ['EURCountries'],
targetedCountries: ['Canada'],
};
const targeting: EpicTargeting = {
...targetingDefault,
countryCode: 'DE',
};

const got = matchesCountryGroups.test(test, targeting);

expect(got).toBe(true);
});

it('should pass if user is in targeted country', () => {
const test: EpicTest = {
...testDefault,
locations: [],
targetedCountries: ['Germany'],
};
const targeting: EpicTargeting = {
...targetingDefault,
countryCode: 'DE',
};

const got = matchesCountryGroups.test(test, targeting);

expect(got).toBe(true);
});

it('should pass if user is in both country group or targeted country', () => {
const test: EpicTest = {
...testDefault,
locations: ['EURCountries'],
targetedCountries: ['Germany'],
};
const targeting: EpicTargeting = {
...targetingDefault,
countryCode: 'DE',
};

const got = matchesCountryGroups.test(test, targeting);

expect(got).toBe(true);
});

it('should fail if user is not in country group or targeted country', () => {
const test: EpicTest = {
...testDefault,
locations: ['EURCountries'],
targetedCountries: ['New Zealand'],
};
const targeting: EpicTargeting = {
...targetingDefault,
countryCode: 'GB',
};

const got = matchesCountryGroups.test(test, targeting);

expect(got).toBe(false);
});
});

describe('withinArticleViewedSettings filter', () => {
Expand Down
22 changes: 21 additions & 1 deletion src/shared/lib/geolocation.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { getCountryName, getLocalCurrencySymbol, addRegionIdToSupportUrl } from './geolocation';
import {
getCountryName,
getLocalCurrencySymbol,
addRegionIdToSupportUrl,
getCountryCodeFromName,
} from './geolocation';

describe('getLocalCurrencySymbol', () => {
const currencySymbolTests = [
Expand Down Expand Up @@ -83,3 +88,18 @@ describe('addRegionIdToSupportUrl', () => {
expect(modifiedUrl).toEqual(nonconformingUrl);
});
});

describe('get Country Code from name', () => {
const testCases = [
{ input: 'the UK', expected: 'GB' },
{ input: 'the Czech Republic', expected: 'CZ' },
{ input: 'France', expected: 'FR' },
{ input: 'Nonexistent Country', expected: undefined },
];

testCases.forEach(({ input, expected }) => {
it(`returns ${expected} for country name ${input}`, () => {
expect(getCountryCodeFromName(input)).toEqual(expected);
});
});
});
43 changes: 24 additions & 19 deletions src/shared/lib/geolocation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const CountryGroupId = [
export type CountryGroupId = (typeof CountryGroupId)[number];

export const countryGroupIdSchema = z.enum(CountryGroupId);
export const targetedCountriesSchema = z.array(z.string());
//export const targetedCountriesSchema = z.string();

// Used to internationalise 'Support the Guardian' links
export type SupportRegionId = 'UK' | 'US' | 'AU' | 'EU' | 'INT' | 'NZ' | 'CA';
Expand Down Expand Up @@ -561,7 +561,6 @@ export const countryCodeToCountryGroupId = (countryCode?: string): CountryGroupI
const foundCountryGroupId = availableCountryGroupIds.find((countryGroupId) =>
countryGroups[countryGroupId].countries.includes(countryCode ?? ''),
);

return foundCountryGroupId || 'International';
};

Expand All @@ -570,29 +569,29 @@ export const inCountryGroups = (
countryGroups: CountryGroupId[] = [],
countryNames: string[] = [], // Accepts country names
): boolean => {
// Always True if no locations or targeted countries set for the test
// Always True if no locations or targeted countries set for the test (so always displays epic)
if (countryGroups.length === 0 && countryNames.length === 0) {
return true;
}

// Always False if user location unknown but test has locations set
// Always false if user location unknown but test has locations set (so never displays epic unless in country)
if (!countryCode) {
return false;
}

const upperCaseCountryCode = countryCode.toUpperCase();
console.log('upperCaseCountryCode', upperCaseCountryCode);

// Convert country names to codes
const countryCodesFromNames = mapCountryNamesToCodes(countryNames);

// Check if the country is directly targeted by name (converted to code)
if (countryCodesFromNames.includes(upperCaseCountryCode)) {
// Check if the country belongs to the specified country groups
if (countryGroups.includes(countryCodeToCountryGroupId(countryCode.toUpperCase()))) {
return true;
}

// Check if the country belongs to the specified country groups
return countryGroups.includes(countryCodeToCountryGroupId(upperCaseCountryCode));
// Check if the country is in the targeted countries by name
for (const name of countryNames) {
const code = getCountryCodeFromName(name);
if (code && code.toUpperCase() === countryCode.toUpperCase()) {
return true;
}
}

return false;
};

const defaultCurrencySymbol = '£';
Expand All @@ -618,10 +617,6 @@ export const getCountryName = (geolocation?: string): string | undefined => {
return undefined;
};

const mapCountryNamesToCodes = (names: string[]): string[] => {
return names.map((name) => countryNames[name] || null).filter((code): code is string => !!code);
};

const countryCodeToSupportRegionId = (countryCode: string): SupportRegionId =>
countryGroups[countryCodeToCountryGroupId(countryCode)]?.supportRegionId;

Expand All @@ -641,3 +636,13 @@ export const addRegionIdToSupportUrl = (originalUrl: string, countryCode?: strin

return originalUrl;
};

const countryNameToCodeMap: Record<string, string> = {};
for (const [code, name] of Object.entries(countryNames)) {
countryNameToCodeMap[name] = code;
}

// Function to get country code from country name
export const getCountryCodeFromName = (countryName: string): string | undefined => {
return countryNameToCodeMap[countryName];
};

0 comments on commit e79a33b

Please sign in to comment.