-
Notifications
You must be signed in to change notification settings - Fork 8.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[i18n] Test EUI i18n tokens coverage (#106377)
- Loading branch information
Showing
5 changed files
with
194 additions
and
440 deletions.
There are no files selected for viewing
8 changes: 4 additions & 4 deletions
8
src/core/public/i18n/__snapshots__/i18n_service.test.tsx.snap
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
jest.mock('@kbn/i18n'); | ||
|
||
import { i18n } from '@kbn/i18n'; | ||
|
||
import i18ntokens from '@elastic/eui/i18ntokens.json'; | ||
import { getEuiContextMapping } from './i18n_eui_mapping'; | ||
|
||
/** Regexp to find {values} usage */ | ||
const VALUES_REGEXP = /\{\w+\}/; | ||
|
||
describe('@elastic/eui i18n tokens', () => { | ||
const i18nTranslateMock = jest | ||
.fn() | ||
.mockImplementation((id, { defaultMessage }) => defaultMessage); | ||
i18n.translate = i18nTranslateMock; | ||
|
||
const euiContextMapping = getEuiContextMapping(); | ||
|
||
test('all tokens are mapped', () => { | ||
// Extract the tokens from the EUI library: We need to uniq them because they might be duplicated | ||
const euiTokensFromLib = [...new Set(i18ntokens.map(({ token }) => token))]; | ||
const euiTokensFromMapping = Object.keys(euiContextMapping); | ||
|
||
expect(euiTokensFromMapping.sort()).toStrictEqual(euiTokensFromLib.sort()); | ||
}); | ||
|
||
test('tokens that include {word} should be mapped to functions', () => { | ||
const euiTokensFromLibWithValues = i18ntokens.filter(({ defString }) => | ||
VALUES_REGEXP.test(defString) | ||
); | ||
const euiTokensFromLib = [...new Set(euiTokensFromLibWithValues.map(({ token }) => token))]; | ||
const euiTokensFromMapping = Object.entries(euiContextMapping) | ||
.filter(([, value]) => typeof value === 'function') | ||
.map(([key]) => key); | ||
|
||
expect(euiTokensFromMapping.sort()).toStrictEqual(euiTokensFromLib.sort()); | ||
}); | ||
|
||
i18ntokens.forEach(({ token, defString }) => { | ||
describe(`Token "${token}"`, () => { | ||
let i18nTranslateCall: [ | ||
string, | ||
{ defaultMessage: string; values?: object; description?: string } | ||
]; | ||
|
||
beforeAll(() => { | ||
// If it's a function, call it, so we have the mock to register the call. | ||
const entry = euiContextMapping[token as keyof typeof euiContextMapping]; | ||
const translationOutput = typeof entry === 'function' ? entry({}) : entry; | ||
|
||
// If it's a string, it comes from i18n.translate call | ||
if (typeof translationOutput === 'string') { | ||
// find the call in the mocks | ||
i18nTranslateCall = i18nTranslateMock.mock.calls.find( | ||
([kbnToken]) => kbnToken === `core.${token}` | ||
); | ||
} else { | ||
// Otherwise, it's a fn returning `FormattedMessage` component => read the props | ||
const { id, defaultMessage, values } = translationOutput.props; | ||
i18nTranslateCall = [id, { defaultMessage, values }]; | ||
} | ||
}); | ||
|
||
test('a translation should be registered as `core.{TOKEN}`', () => { | ||
expect(i18nTranslateCall).not.toBeUndefined(); | ||
}); | ||
|
||
test('defaultMessage is in sync with defString', () => { | ||
// Clean up typical errors from the `@elastic/eui` extraction token tool | ||
const normalizedDefString = defString | ||
// Quoted words should use double-quotes | ||
.replace(/\s'/g, ' "') | ||
.replace(/'\s/g, '" ') | ||
// Should not include break-lines | ||
.replace(/\n/g, '') | ||
// Should trim extra spaces | ||
.replace(/\s{2,}/g, ' ') | ||
.trim(); | ||
|
||
expect(i18nTranslateCall[1].defaultMessage).toBe(normalizedDefString); | ||
}); | ||
|
||
test('values should match', () => { | ||
const valuesFromEuiLib = defString.match(new RegExp(VALUES_REGEXP, 'g')) || []; | ||
const receivedValuesInMock = Object.keys(i18nTranslateCall[1].values ?? {}).map( | ||
(key) => `{${key}}` | ||
); | ||
expect(receivedValuesInMock.sort()).toStrictEqual(valuesFromEuiLib.sort()); | ||
}); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.