Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 46 additions & 7 deletions testsuite/tests/util/Entities.test.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,64 @@
import { describe, test, expect } from '@jest/globals';
import * as Entities from '#js/util/Entities.js';
import { handleRetriesFor } from '#js/util/Retries.js';
import { mathjax } from '#js/mathjax.js';
import '#js/util/asyncLoad/esm.js';
import '@mathjax/src/components/require.mjs';

describe('Entities translation', () => {
test('translate()', async () => {
test('translate()', () => {
expect(Entities.translate('a')).toBe('a');
expect(Entities.translate('a')).toBe('a');
expect(Entities.translate('&')).toBe('&');
});

test('Unknown entity', async () => {
await expect(
handleRetriesFor(() => Entities.translate('&xyz;'))
mathjax.handleRetriesFor(() => Entities.translate('&xyz;'))
).resolves.toBe('&xyz;'); // no such entity
});

test('Load entity files', async () => {
await expect(
handleRetriesFor(() => Entities.translate('≈'))
mathjax.handleRetriesFor(() => Entities.translate('≈'))
).resolves.toBe('\u2248'); // load a.js
await expect(
handleRetriesFor(() => Entities.translate('ℬ'))
mathjax.handleRetriesFor(() => Entities.translate('ℬ'))
).resolves.toBe('\u212C'); // load scr.js
Entities.remove('approx');
expect(Entities.translate('≈')).toBe('≈'); // undefined entities remain unchanged
Entities.options.loadMissingEntities = false;
expect(Entities.translate('⋀')).toBe('⋀'); // don't load b.js
Entities.options.loadMissingEntities = true;
});

test('Remove entity', () => {
Entities.remove('approx');
expect(Entities.translate('≈')).toBe('≈'); // undefined entities remain unchanged
});

test('Synchronous load', () => {
const asyncLoad = mathjax.asyncLoad;
const REQUIRE = require;
mathjax.asyncIsSynchronous = true;
mathjax.asyncLoad = (file) => REQUIRE(`#js/../cjs/${file}`);
expect((() => {
try {
Entities.translate('©');
return 'success';
} catch (_err) {
return 'failed';
}
})()).toBe('success');
mathjax.asyncLoad = asyncLoad;
mathjax.asyncIsSynchronous = false;
});

test('AsycLoad retries', () => {
expect((() => {
try {
Entities.translate('÷');
return 'success';
} catch (_err) {
return 'failed';
}
})()).toBe('failed');
});
});
17 changes: 10 additions & 7 deletions ts/util/Entities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@
* @author dpvc@mathjax.org (Davide Cervone)
*/

import { retryAfter } from './Retries.js';
import { asyncLoad } from './AsyncLoad.js';
import { mathjax } from '../mathjax.js';
import { OptionList } from './Options.js';

/**
Expand Down Expand Up @@ -493,7 +492,7 @@ export function translate(text: string): string {
*
* @param {string} match The complete entity being replaced
* @param {string} entity The name of the entity to be replaced
* @returns {string} The unicode character for the entity, or the entity name (if none found)
* @returns {string} The unicode character for the entity, or the entity name (if none found)
*/
function replace(match: string, entity: string): string {
if (entity.charAt(0) === '#') {
Expand All @@ -503,12 +502,16 @@ function replace(match: string, entity: string): string {
return entities[entity];
}
if (options['loadMissingEntities']) {
const file = entity.match(/^[a-zA-Z](fr|scr|opf)$/)
? RegExp.$1
: entity.charAt(0).toLowerCase();
const file =
entity.match(/^[a-zA-Z](fr|scr|opf)$/)?.[1] ??
entity.charAt(0).toLowerCase();
if (!loaded[file]) {
loaded[file] = true;
retryAfter(asyncLoad('./util/entities/' + file + '.js'));
const promise = mathjax.asyncLoad(`./util/entities/${file}.js`);
if (mathjax.asyncIsSynchronous) {
return replace(match, entity);
}
mathjax.retryAfter(promise);
}
}
return match;
Expand Down