diff --git a/addons/voice/ui/test/library.test.mjs b/addons/voice/ui/test/library.test.mjs index 4cce6684d..8795365eb 100644 --- a/addons/voice/ui/test/library.test.mjs +++ b/addons/voice/ui/test/library.test.mjs @@ -13,14 +13,14 @@ const { renderToString } = require('react-dom/server') test('library: the first paint of the library page has the core test id', async () => { const { mod, sdk } = await load() const addon = await mod.createAddon(sdk) - const html = renderToString(React.createElement(addon.Component, { page: 'library', path: '' })) + const html = renderToString(React.createElement(addon.Component, { page: 'voice', path: 'library' })) assert.match(html, /data-testid="voice-library"/) }) test('create: the first paint of the create page has the core test id', async () => { const { mod, sdk } = await load() const addon = await mod.createAddon(sdk) - const html = renderToString(React.createElement(addon.Component, { page: 'create', path: '' })) + const html = renderToString(React.createElement(addon.Component, { page: 'voice', path: 'library/new' })) assert.match(html, /data-testid="voice-profile-create"/) }) @@ -47,12 +47,12 @@ function queuedEffects() { } const profileCalls = (calls) => calls.filter(([url]) => /^\/api\/(voice-profiles|models|operations)/.test(url)) -for (const page of ['library', 'create']) { +for (const [page, path] of [['library', 'library'], ['create', 'library/new']]) { test(`${page}: a viewer who is not an administrator sees the off notice and the page makes no call`, async () => { const q = queuedEffects() const { mod, sdk, calls } = await load({ React: q.React, viewer: { isAdmin: () => false, hasFeature: () => true } }) const addon = await mod.createAddon(sdk) - const html = renderToString(React.createElement(addon.Component, { page, path: '' })) + const html = renderToString(React.createElement(addon.Component, { page: 'voice', path })) q.run() await new Promise(r => setTimeout(r, 20)) assert.match(html, /data-testid="voice-admin-only"/) @@ -65,7 +65,7 @@ test('library: an administrator gets the library and the profile list is request const q = queuedEffects() const { mod, sdk, calls } = await load({ React: q.React }) const addon = await mod.createAddon(sdk) - const html = renderToString(React.createElement(addon.Component, { page: 'library', path: '' })) + const html = renderToString(React.createElement(addon.Component, { page: 'voice', path: 'library' })) q.run() await new Promise(r => setTimeout(r, 20)) assert.doesNotMatch(html, /voice-admin-only/) diff --git a/addons/voice/ui/test/recognition.test.mjs b/addons/voice/ui/test/recognition.test.mjs index a655316c7..7e17acfdc 100644 --- a/addons/voice/ui/test/recognition.test.mjs +++ b/addons/voice/ui/test/recognition.test.mjs @@ -13,7 +13,7 @@ const { renderToString } = require('react-dom/server') test('recognition: the first paint has the core test id and the page title', async () => { const { mod, sdk } = await load() const addon = await mod.createAddon(sdk) - const html = renderToString(React.createElement(addon.Component, { page: 'recognition', path: '' })) + const html = renderToString(React.createElement(addon.Component, { page: 'voice', path: 'recognition' })) assert.match(html, /data-testid="voices-page"/) assert.match(html, /Voices/) }) @@ -21,7 +21,7 @@ test('recognition: the first paint has the core test id and the page title', asy test('recognition: a viewer without voice_recognition gets the off notice, not the workbench', async () => { const { mod, sdk } = await load({ viewer: { isAdmin: () => false, hasFeature: (f) => f !== 'voice_recognition' } }) const addon = await mod.createAddon(sdk) - const html = renderToString(React.createElement(addon.Component, { page: 'recognition', path: '' })) + const html = renderToString(React.createElement(addon.Component, { page: 'voice', path: 'recognition' })) assert.match(html, /data-testid="voice-off"/) assert.doesNotMatch(html, /idn-bench/) }) @@ -34,23 +34,23 @@ test('recognition: the model of the path reaches the model selection', async () components.ModelSelector = (p) => { seen.push(p.value); return React.createElement('div') } const { mod, sdk } = await load({ components }) const addon = await mod.createAddon(sdk) - renderToString(React.createElement(addon.Component, { page: 'recognition', path: 'speechbrain' })) + renderToString(React.createElement(addon.Component, { page: 'voice', path: 'recognition/speechbrain' })) assert.deepEqual(seen, ['speechbrain']) }) -test('recognition: a viewer who is not an administrator still gets the workbench and no speech voices tab', async () => { +test('recognition: a viewer who is not an administrator still gets the workbench and no Library tab', async () => { const { mod, sdk } = await load({ viewer: { isAdmin: () => false, hasFeature: () => true } }) const addon = await mod.createAddon(sdk) - const html = renderToString(React.createElement(addon.Component, { page: 'recognition', path: '' })) + const html = renderToString(React.createElement(addon.Component, { page: 'voice', path: 'recognition' })) assert.match(html, /idn-bench/) - assert.doesNotMatch(html, /Speech voices/) + assert.doesNotMatch(html, /Library/) }) -test('recognition: an administrator sees the three tabs', async () => { +test('recognition: an administrator sees the four tabs', async () => { const { mod, sdk } = await load() const addon = await mod.createAddon(sdk) - const html = renderToString(React.createElement(addon.Component, { page: 'recognition', path: '' })) - for (const label of ['Speakers', 'Speech voices', 'From a recording']) assert.ok(html.includes(label), label) + const html = renderToString(React.createElement(addon.Component, { page: 'voice', path: 'recognition' })) + for (const label of ['Recognition', 'Library', 'Text to speech', 'From a recording']) assert.ok(html.includes(label), label) }) test('recognition: the bundle carries no face-only canvas and no host import', async () => { diff --git a/addons/voice/ui/test/render.test.mjs b/addons/voice/ui/test/render.test.mjs index 3b6350791..c49f44ff8 100644 --- a/addons/voice/ui/test/render.test.mjs +++ b/addons/voice/ui/test/render.test.mjs @@ -19,7 +19,7 @@ export async function load(extra = {}) { const calls = [] const controller = new AbortController() const sdk = createHostSDK({ - addonId: 'voice', generation: 1, signal: controller.signal, pages: ['recognition', 'library', 'create', 'speech'], + addonId: 'voice', generation: 1, signal: controller.signal, pages: ['voice', 'recognition', 'library', 'create', 'speech'], host: { React, components: Object.fromEntries(['Button', 'Spinner', 'EmptyState', 'Badge', 'Stack', 'Text', 'PageHeader', 'ConfirmDialog', 'ErrorWithTraceLink', 'ModelSelector', 'MediaInput', 'WaveformPlayer', 'DistributionBars', 'EmbeddingInspector', 'TabSwitch'].map(n => [n, stub(n === 'PageHeader' ? 'header' : 'div')])), @@ -50,18 +50,36 @@ test('render: an unknown page draws nothing', async () => { assert.equal(renderToString(React.createElement(addon.Component, { page: 'nope', path: '' })), '') }) -test('render: the manifest declares the four pages, the main page and SDK 2', async () => { +test('render: the manifest declares one page in the navigation, the older pages, the main page and SDK 2', async () => { const { readFileSync } = await import('node:fs') const m = JSON.parse(readFileSync(join(here, '../../manifest.json'), 'utf8')) assert.equal(m.id, 'voice') - assert.deepEqual(m.capabilities.ui.pages, ['recognition', 'library', 'create', 'speech']) - assert.equal(m.capabilities.ui.mainPage, 'recognition') + assert.deepEqual(m.capabilities.ui.pages, ['voice', 'recognition', 'library', 'create', 'speech']) + assert.deepEqual(m.capabilities.ui.navigation, ['voice']) + assert.equal(m.capabilities.ui.mainPage, 'voice') assert.deepEqual(m.capabilities.ui.sdk, { min: 2, max: 2 }) assert.deepEqual(m.capabilities.tools ?? [], []) }) -test('render: a registered page is drawn with its path', async () => { +test('render: a tab is drawn with the rest of the path and the tab strip', async () => { const { mod, sdk } = await load() - const addon = await mod.createAddon(sdk, { pages: { speech: ({ path }) => React.createElement('p', null, `page:${path}`) } }) - assert.equal(renderToString(React.createElement(addon.Component, { page: 'speech', path: 'abc' })), '
page:abc
') + const addon = await mod.createAddon(sdk, { pages: { speech: ({ path, tabs }) => React.createElement('div', null, tabs, React.createElement('p', null, `page:${path}`)) } }) + const html = renderToString(React.createElement(addon.Component, { page: 'voice', path: 'speech/abc' })) + assert.match(html, /page:abc<\/p>/) + assert.match(html, /data-testid="voice-tabs"/) + assert.match(html, /data-tab="speech"[^>]*aria-selected="true"/) +}) + +test('render: no tab in the path opens the recognition tab', async () => { + const { mod, sdk } = await load() + const addon = await mod.createAddon(sdk) + assert.match(renderToString(React.createElement(addon.Component, { page: 'voice', path: '' })), /data-testid="voices-page"/) +}) + +test('render: an older page name draws nothing itself; the shell sends it to its tab', async () => { + const { mod, sdk } = await load() + const addon = await mod.createAddon(sdk) + for (const page of ['recognition', 'library', 'create', 'speech']) { + assert.equal(renderToString(React.createElement(addon.Component, { page, path: '' })), '', page) + } }) diff --git a/addons/voice/ui/test/speech.test.mjs b/addons/voice/ui/test/speech.test.mjs index 995c675a3..5a5f01b99 100644 --- a/addons/voice/ui/test/speech.test.mjs +++ b/addons/voice/ui/test/speech.test.mjs @@ -13,7 +13,7 @@ const { renderToString } = require('react-dom/server') test('speech: the first paint shows the title and the text box', async () => { const { mod, sdk } = await load() const addon = await mod.createAddon(sdk) - const html = renderToString(React.createElement(addon.Component, { page: 'speech', path: '' })) + const html = renderToString(React.createElement(addon.Component, { page: 'voice', path: 'speech' })) assert.match(html, /data-testid="voice-speech"/) assert.match(html, /