PronounsPage/test/helpers.test.ts
2025-05-03 18:11:56 +02:00

228 lines
8.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { describe, expect, test } from 'vitest';
import {
escapeControlSymbols,
unescapeControlSymbols,
convertPronunciationStringToSsml,
convertPronunciationStringToNarakeetFormat,
escapePronunciationString,
isGrantedForUser,
} from '../src/helpers.ts';
import type { PermissionArea } from '~/src/helpers.ts';
const controlSymbols = [
{
description: 'slashes',
unescaped: 'w/o n/A',
escaped: 'w`/o n`/A',
},
{
description: 'ampersands',
unescaped: 'me & you',
escaped: 'me `& you',
},
{
description: 'backticks',
unescaped: '`code` in markdown',
escaped: '``code`` in markdown',
},
{
description: 'commas',
unescaped: 'me, you',
escaped: 'me`, you',
},
{
description: 'pipes',
unescaped: '0 | 1',
escaped: '0 `| 1',
},
];
describe('when escaping control symbols', () => {
test('safely handles null', () => {
expect(escapeControlSymbols(null)).toBeNull();
});
test.each(controlSymbols)('$description get escaped with `', ({ unescaped, escaped }) => {
expect(escapeControlSymbols(unescaped)).toBe(escaped);
});
});
describe('when unescaping control symbols', () => {
test('safely handles null', () => {
expect(unescapeControlSymbols(null)).toBeNull();
});
test.each(controlSymbols)('$description get unescaped', ({ unescaped, escaped }) => {
expect(unescapeControlSymbols(escaped)).toBe(unescaped);
});
});
describe('when escaping pronunciation to SSML', () => {
test.each([
{
description: 'slashes get escaped',
text: 'w/o n/A',
pronunciationString: String.raw`w\/o n\/A`,
},
{
description: 'backslashes get escaped',
text: String.raw`\n is the symbol for a newline, \t for a tab`,
pronunciationString: String.raw`\\n is the symbol for a newline, \\t for a tab`,
},
])('$description', ({ text, pronunciationString }) => {
expect(escapePronunciationString(text)).toBe(pronunciationString);
});
});
describe('when converting pronunciation', () => {
test.each([
{
description: 'simple text is passed as-is',
pronunciationString: 'text',
ssml: '<speak>text</speak>',
},
{
description: 'slashes describe IPA phonemes',
pronunciationString: '/ðeɪ/',
ssml: '<speak><phoneme alphabet="ipa" ph="ðeɪ"></phoneme></speak>',
},
{
description: 'simple text and slashes can be combined',
pronunciationString: '/ðeɪ/ are',
ssml: '<speak><phoneme alphabet="ipa" ph="ðeɪ"></phoneme> are</speak>',
},
{
description: 'slashes can be escaped at front',
pronunciationString: String.raw`w\/o, n/A`,
ssml: '<speak>w/o, n/A</speak>',
},
{
description: 'slashes can be escaped at back',
pronunciationString: String.raw`w/o, n\/A`,
ssml: '<speak>w/o, n/A</speak>',
},
{
description: 'provided HTML is escaped',
pronunciationString: '<break time="1s"/>',
ssml: '<speak>&lt;break time=&quot;1s&quot;/&gt;</speak>',
},
])('$description', ({ pronunciationString, ssml }) => {
expect(convertPronunciationStringToSsml(pronunciationString)).toBe(ssml);
});
});
describe('when converting pronunciation to Narakeet format', () => {
test.each([
{
description: 'simple text is passed as-is',
pronunciationString: 'text',
narakeet: 'text',
},
{
description: 'slashes describe IPA phonemes',
pronunciationString: '/ðeɪ/',
narakeet: '[ðeɪ]{ipa}',
},
{
description: 'simple text and slashes can be combined',
pronunciationString: '/ðeɪ/ are',
narakeet: '[ðeɪ]{ipa} are',
},
{
description: 'slashes can be escaped at front',
pronunciationString: String.raw`w\/o, n/A`,
narakeet: 'w/o, n/A',
},
{
description: 'slashes can be escaped at back',
pronunciationString: String.raw`w/o, n\/A`,
narakeet: 'w/o, n/A',
},
{
description: 'provided HTML is escaped',
pronunciationString: '<break time="1s"/>',
narakeet: '&lt;break time=&quot;1s&quot;/&gt;',
},
])('$description', ({ pronunciationString, narakeet }) => {
expect(convertPronunciationStringToNarakeetFormat(pronunciationString)).toBe(narakeet);
});
});
class GrantTest {
constructor(
public readonly givenRoles: string,
public readonly requestedLocale: string,
public readonly requestedArea: PermissionArea,
public readonly granted: boolean,
) {}
}
describe('access control', () => {
const SUPER_ADMIN = '*';
const LOCALE_ADMIN = 'pl-*|fr-nouns';
const SUPER_ADMIN_PLUS_RESTRICTED = '*|*-code';
const SECTION_ADMIN = '*-terms';
const EXTERNAL_CONTRIBUTOR = '*-external';
const GUEST = '';
test.each([
new GrantTest(SUPER_ADMIN, 'en', '*', true),
new GrantTest(SUPER_ADMIN, 'en', 'panel', true),
new GrantTest(SUPER_ADMIN, 'en', 'nouns', true),
new GrantTest(SUPER_ADMIN, 'en', 'code', false), // restricted area
new GrantTest(SUPER_ADMIN, 'en', 'external', true),
new GrantTest(SUPER_ADMIN, 'en', '', true),
new GrantTest(SUPER_ADMIN_PLUS_RESTRICTED, 'en', '*', true),
new GrantTest(SUPER_ADMIN_PLUS_RESTRICTED, 'en', 'panel', true),
new GrantTest(SUPER_ADMIN_PLUS_RESTRICTED, 'en', 'nouns', true),
new GrantTest(SUPER_ADMIN_PLUS_RESTRICTED, 'en', 'code', true),
new GrantTest(SUPER_ADMIN_PLUS_RESTRICTED, 'en', 'external', true),
new GrantTest(SUPER_ADMIN_PLUS_RESTRICTED, 'en', '', true),
new GrantTest(LOCALE_ADMIN, 'en', '*', false), // super-admin area
new GrantTest(LOCALE_ADMIN, 'en', 'panel', false), // wrong locale
new GrantTest(LOCALE_ADMIN, 'en', 'nouns', false),
new GrantTest(LOCALE_ADMIN, 'en', 'code', false),
new GrantTest(LOCALE_ADMIN, 'en', 'external', false),
new GrantTest(LOCALE_ADMIN, 'en', '', false),
new GrantTest(LOCALE_ADMIN, 'pl', 'panel', true),
new GrantTest(LOCALE_ADMIN, 'pl', 'nouns', true),
new GrantTest(LOCALE_ADMIN, 'pl', 'code', false), // restricted area
new GrantTest(LOCALE_ADMIN, 'pl', 'external', true),
new GrantTest(LOCALE_ADMIN, 'pl', '', true),
new GrantTest(LOCALE_ADMIN, 'fr', 'nouns', true),
new GrantTest(LOCALE_ADMIN, 'fr', 'inclusive', false), // wrong area
new GrantTest(LOCALE_ADMIN, 'fr', '', true),
new GrantTest(SECTION_ADMIN, 'en', '*', false),
new GrantTest(SECTION_ADMIN, 'en', 'panel', true),
new GrantTest(SECTION_ADMIN, 'en', 'nouns', false),
new GrantTest(SECTION_ADMIN, 'en', 'terms', true),
new GrantTest(SECTION_ADMIN, 'en', 'code', false),
new GrantTest(SECTION_ADMIN, 'en', 'external', false),
new GrantTest(SECTION_ADMIN, 'pl', '*', false),
new GrantTest(SECTION_ADMIN, 'pl', 'panel', true),
new GrantTest(SECTION_ADMIN, 'pl', 'nouns', false),
new GrantTest(SECTION_ADMIN, 'pl', 'terms', true),
new GrantTest(SECTION_ADMIN, 'pl', 'code', false),
new GrantTest(SECTION_ADMIN, 'pl', 'external', false),
new GrantTest(EXTERNAL_CONTRIBUTOR, 'en', '*', false),
new GrantTest(EXTERNAL_CONTRIBUTOR, 'en', 'panel', false),
new GrantTest(EXTERNAL_CONTRIBUTOR, 'en', 'nouns', false),
new GrantTest(EXTERNAL_CONTRIBUTOR, 'en', 'code', false),
new GrantTest(EXTERNAL_CONTRIBUTOR, 'en', 'external', true),
new GrantTest(EXTERNAL_CONTRIBUTOR, 'en', '', false),
new GrantTest(GUEST, 'en', '*', false),
new GrantTest(GUEST, 'en', 'panel', false),
new GrantTest(GUEST, 'en', 'nouns', false),
new GrantTest(GUEST, 'en', 'code', false),
new GrantTest(GUEST, 'en', 'external', false),
new GrantTest(GUEST, 'en', '', false),
])('user with roles $givenRoles requesting $requestedArea in $requestedLocale', ({ givenRoles, requestedLocale, requestedArea, granted }) => {
expect(isGrantedForUser({ roles: givenRoles }, requestedLocale, requestedArea)).toBe(granted);
});
});