Skip to content

Commit

Permalink
Merge pull request #37208 from JKobrynski/migrateGroup1FilesToTypeScript
Browse files Browse the repository at this point in the history
[No QA] [TS Migration] Migrate enhanceParametersTest.js, LocalizeTests.js, nativeVersionUpdaterTest.js, createOrUpdateStagingDeployTest.js, TranslateTest.js test to TypeScript
  • Loading branch information
puneetlath authored Mar 6, 2024
2 parents aaa1795 + 80dbd5a commit 2ff35c4
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 36 deletions.
9 changes: 9 additions & 0 deletions src/utils/arrayDifference.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* This function is an equivalent of _.difference, it takes two arrays and returns the difference between them.
* It returns an array of items that are in the first array but not in the second array.
*/
function arrayDifference<TItem>(array1: TItem[], array2: TItem[]): TItem[] {
return [array1, array2].reduce((a, b) => a.filter((c) => !b.includes(c)));
}

export default arrayDifference;
File renamed without changes.
69 changes: 39 additions & 30 deletions tests/unit/TranslateTest.js → tests/unit/TranslateTest.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import {AnnotationError} from '@actions/core';
import _ from 'underscore';
import CONFIG from '../../src/CONFIG';
import CONST from '../../src/CONST';
import * as translations from '../../src/languages/translations';
import * as Localize from '../../src/libs/Localize';

const originalTranslations = _.clone(translations);
translations.default = {
/* eslint-disable @typescript-eslint/naming-convention */
import CONFIG from '@src/CONFIG';
import CONST from '@src/CONST';
import * as translations from '@src/languages/translations';
import type {TranslationFlatObject, TranslationPaths} from '@src/languages/types';
import * as Localize from '@src/libs/Localize';
import asMutable from '@src/types/utils/asMutable';
import arrayDifference from '@src/utils/arrayDifference';

const originalTranslations = {...translations};

asMutable(translations).default = {
[CONST.LOCALES.EN]: translations.flattenObject({
testKey1: 'English',
testKey2: 'Test Word 2',
Expand All @@ -24,80 +27,86 @@ translations.default = {

describe('translate', () => {
it('Test present key in full locale', () => {
expect(Localize.translate(CONST.LOCALES.ES_ES, 'testKey1')).toBe('Spanish ES');
expect(Localize.translate(CONST.LOCALES.ES_ES, 'testKey1' as TranslationPaths)).toBe('Spanish ES');
});

it('Test when key is not found in full locale, but present in language', () => {
expect(Localize.translate(CONST.LOCALES.ES_ES, 'testKey2')).toBe('Spanish Word 2');
expect(Localize.translate(CONST.LOCALES.ES, 'testKey2')).toBe('Spanish Word 2');
expect(Localize.translate(CONST.LOCALES.ES_ES, 'testKey2' as TranslationPaths)).toBe('Spanish Word 2');
expect(Localize.translate(CONST.LOCALES.ES, 'testKey2' as TranslationPaths)).toBe('Spanish Word 2');
});

it('Test when key is not found in full locale and language, but present in default', () => {
expect(Localize.translate(CONST.LOCALES.ES_ES, 'testKey3')).toBe('Test Word 3');
expect(Localize.translate(CONST.LOCALES.ES_ES, 'testKey3' as TranslationPaths)).toBe('Test Word 3');
});

test('Test when key is not found in default', () => {
expect(() => Localize.translate(CONST.LOCALES.ES_ES, 'testKey4')).toThrow(Error);
expect(() => Localize.translate(CONST.LOCALES.ES_ES, 'testKey4' as TranslationPaths)).toThrow(Error);
});

test('Test when key is not found in default (Production Mode)', () => {
const ORIGINAL_IS_IN_PRODUCTION = CONFIG.IS_IN_PRODUCTION;
CONFIG.IS_IN_PRODUCTION = true;
expect(Localize.translate(CONST.LOCALES.ES_ES, 'testKey4')).toBe('testKey4');
CONFIG.IS_IN_PRODUCTION = ORIGINAL_IS_IN_PRODUCTION;
asMutable(CONFIG).IS_IN_PRODUCTION = true;
expect(Localize.translate(CONST.LOCALES.ES_ES, 'testKey4' as TranslationPaths)).toBe('testKey4');
asMutable(CONFIG).IS_IN_PRODUCTION = ORIGINAL_IS_IN_PRODUCTION;
});

it('Test when translation value is a function', () => {
const expectedValue = 'With variable Test Variable';
const testVariable = 'Test Variable';
expect(Localize.translate(CONST.LOCALES.EN, 'testKeyGroup.testFunction', {testVariable})).toBe(expectedValue);
// @ts-expect-error - TranslationPaths doesn't include testKeyGroup.testFunction as a valid key
expect(Localize.translate(CONST.LOCALES.EN, 'testKeyGroup.testFunction' as TranslationPaths, {testVariable})).toBe(expectedValue);
});
});

describe('Translation Keys', () => {
function traverseKeyPath(source, path, keyPaths) {
const pathArray = keyPaths || [];
function traverseKeyPath(source: TranslationFlatObject, path?: string, keyPaths?: string[]): string[] {
const pathArray = keyPaths ?? [];
const keyPath = path ? `${path}.` : '';
_.each(_.keys(source), (key) => {
if (_.isObject(source[key]) && !_.isFunction(source[key])) {
(Object.keys(source) as Array<keyof TranslationFlatObject>).forEach((key) => {
if (typeof source[key] === 'object' && typeof source[key] !== 'function') {
// @ts-expect-error - We are modifying the translations object for testing purposes
traverseKeyPath(source[key], keyPath + key, pathArray);
} else {
pathArray.push(keyPath + key);
}
});

return pathArray;
}

const excludeLanguages = [CONST.LOCALES.EN, CONST.LOCALES.ES_ES];
const languages = _.without(_.keys(originalTranslations.default), ...excludeLanguages);
const languages = Object.keys(originalTranslations.default).filter((ln) => !excludeLanguages.some((excludeLanguage) => excludeLanguage === ln));
const mainLanguage = originalTranslations.default.en;
const mainLanguageKeys = traverseKeyPath(mainLanguage);

_.each(languages, (ln) => {
const languageKeys = traverseKeyPath(originalTranslations.default[ln]);
languages.forEach((ln) => {
const languageKeys = traverseKeyPath(originalTranslations.default[ln as keyof typeof originalTranslations.default]);

it(`Does ${ln} locale have all the keys`, () => {
const hasAllKeys = _.difference(mainLanguageKeys, languageKeys);
const hasAllKeys = arrayDifference(mainLanguageKeys, languageKeys);
if (hasAllKeys.length) {
console.debug(`🏹 [ ${hasAllKeys.join(', ')} ] are missing from ${ln}.js`);
AnnotationError(`🏹 [ ${hasAllKeys.join(', ')} ] are missing from ${ln}.js`);
Error(`🏹 [ ${hasAllKeys.join(', ')} ] are missing from ${ln}.js`);
}
expect(hasAllKeys).toEqual([]);
});

it(`Does ${ln} locale have unused keys`, () => {
const hasAllKeys = _.difference(languageKeys, mainLanguageKeys);
const hasAllKeys = arrayDifference(languageKeys, mainLanguageKeys);
if (hasAllKeys.length) {
console.debug(`🏹 [ ${hasAllKeys.join(', ')} ] are unused keys in ${ln}.js`);
AnnotationError(`🏹 [ ${hasAllKeys.join(', ')} ] are unused keys in ${ln}.js`);
Error(`🏹 [ ${hasAllKeys.join(', ')} ] are unused keys in ${ln}.js`);
}
expect(hasAllKeys).toEqual([]);
});
});
});

type ReportContentArgs = {content: string};

describe('flattenObject', () => {
it('It should work correctly', () => {
const func = ({content}) => `This is the content: ${content}`;
const func = ({content}: ReportContentArgs) => `This is the content: ${content}`;
const simpleObject = {
common: {
yes: 'Yes',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/**
* @jest-environment node
*/
import * as core from '@actions/core';

/* eslint-disable @typescript-eslint/naming-convention */
import * as fns from 'date-fns';
import {vol} from 'memfs';
import path from 'path';
Expand All @@ -19,7 +20,9 @@ const mockGetPullRequestsMergedBetween = jest.fn();

beforeAll(() => {
// Mock core module
core.getInput = mockGetInput;
jest.mock('@actions/core', () => ({
getInput: mockGetInput,
}));

// Mock octokit module
const moctokit = {
Expand Down Expand Up @@ -49,8 +52,8 @@ beforeAll(() => {
list: jest.fn().mockResolvedValue([]),
},
},
paginate: jest.fn().mockImplementation((objectMethod) => objectMethod().then(({data}) => data)),
};
paginate: jest.fn().mockImplementation((objectMethod: () => Promise<{data: unknown}>) => objectMethod().then(({data}) => data)),
} as typeof GithubUtils.octokit;
GithubUtils.internalOctokit = moctokit;

// Mock GitUtils
Expand Down Expand Up @@ -295,7 +298,7 @@ describe('createOrUpdateStagingDeployCash', () => {
owner: CONST.GITHUB_OWNER,
repo: CONST.APP_REPO,
issue_number: openStagingDeployCashBefore.number,
// eslint-disable-next-line max-len
// eslint-disable-next-line max-len, @typescript-eslint/naming-convention
html_url: `https://github.com/Expensify/App/issues/${openStagingDeployCashBefore.number}`,
// eslint-disable-next-line max-len
body:
Expand Down Expand Up @@ -371,7 +374,7 @@ describe('createOrUpdateStagingDeployCash', () => {
owner: CONST.GITHUB_OWNER,
repo: CONST.APP_REPO,
issue_number: openStagingDeployCashBefore.number,
// eslint-disable-next-line max-len
// eslint-disable-next-line max-len, @typescript-eslint/naming-convention
html_url: `https://github.com/Expensify/App/issues/${openStagingDeployCashBefore.number}`,
// eslint-disable-next-line max-len
body:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/naming-convention */
import Onyx from 'react-native-onyx';
import CONFIG from '../../src/CONFIG';
import enhanceParameters from '../../src/libs/Network/enhanceParameters';
Expand Down
File renamed without changes.

0 comments on commit 2ff35c4

Please sign in to comment.