PluginProbe
BeyondWords – AI audio for publishers / 7.0.0
BeyondWords – AI audio for publishers v7.0.0
7.1.0 trunk 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.6 4.1.0 4.1.1 4.1.2 4.2.0 4.2.1 4.2.2 4.2.3 4.2.4 4.3.0 4.4.0 4.5.0 4.5.1 4.6.0 4.6.1 4.6.2 4.7.0 All 43 releases
speechkit / src / editor / components / settings-panel / helpers.test.js

helpers.test.js in BeyondWords – AI audio for publishers 7.0.0, at src/editor/components/settings-panel/helpers.test.js

287 lines 7.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* global describe, it, expect */
2
3 /**
4 * Internal dependencies
5 */
6 import {
7 SOURCE_POST,
8 SOURCE_POST_AND_SCRIPT,
9 LEGACY_SOURCE_SCRIPT,
10 OUTPUT_AUDIO,
11 OUTPUT_VIDEO,
12 OUTPUT_AUDIO_AND_VIDEO,
13 EMBED_NONE,
14 EMBED_AUDIO_POST,
15 EMBED_AUDIO_SCRIPT,
16 EMBED_VIDEO_POST,
17 EMBED_VIDEO_SCRIPT,
18 PROJECT_DEFAULT_VALUE,
19 STANDARD_MODEL_KEY,
20 projectDefaultOption,
21 voiceModelLabel,
22 voiceModelKey,
23 getLanguageModels,
24 getSourceOptions,
25 getOutputOptions,
26 normalizeSource,
27 sourceIncludesScript,
28 outputIncludesAudio,
29 outputIncludesVideo,
30 getEmbedOptions,
31 isEmbedValid,
32 getDefaultEmbed,
33 } from './helpers';
34
35 describe( 'projectDefaultOption', () => {
36 it( 'is an empty-valued option', () => {
37 expect( projectDefaultOption() ).toEqual( {
38 label: 'Project default',
39 value: '',
40 } );
41 expect( PROJECT_DEFAULT_VALUE ).toBe( '' );
42 } );
43 } );
44
45 describe( 'voiceModelLabel', () => {
46 it( 'maps known ElevenLabs model slugs', () => {
47 expect( voiceModelLabel( 'eleven_v3' ) ).toBe( 'v3' );
48 expect( voiceModelLabel( 'eleven_multilingual_v2' ) ).toBe(
49 'Multilingual v2'
50 );
51 expect( voiceModelLabel( 'eleven_flash_v2_5' ) ).toBe( 'Flash v2.5' );
52 expect( voiceModelLabel( 'eleven_turbo_v2_5' ) ).toBe( 'Turbo v2.5' );
53 } );
54
55 it( 'title-cases unknown slugs and strips the eleven_ prefix', () => {
56 expect( voiceModelLabel( 'eleven_something_new' ) ).toBe(
57 'Something New'
58 );
59 expect( voiceModelLabel( 'custom_model' ) ).toBe( 'Custom Model' );
60 } );
61 } );
62
63 describe( 'voiceModelKey', () => {
64 it( 'keys ElevenLabs voices by model_id', () => {
65 expect(
66 voiceModelKey( { service: 'ElevenLabs', model_id: 'eleven_v3' } )
67 ).toBe( 'eleven_v3' );
68 } );
69
70 it( 'buckets non-ElevenLabs voices as Standard', () => {
71 expect( voiceModelKey( { service: 'Azure', model_id: null } ) ).toBe(
72 STANDARD_MODEL_KEY
73 );
74 expect( voiceModelKey( { name: 'Ada (Multilingual)' } ) ).toBe(
75 STANDARD_MODEL_KEY
76 );
77 } );
78
79 it( 'buckets ElevenLabs voices without a string model_id as Standard', () => {
80 expect(
81 voiceModelKey( { service: 'ElevenLabs', model_id: null } )
82 ).toBe( STANDARD_MODEL_KEY );
83 } );
84 } );
85
86 describe( 'getLanguageModels', () => {
87 // API order puts a non-default ElevenLabs model first, to prove the default
88 // is pulled to the front while the rest keep their order, Standard last.
89 const voices = [
90 {
91 id: 9001,
92 name: 'Bridget',
93 service: 'ElevenLabs',
94 model_id: 'eleven_flash_v2_5',
95 },
96 {
97 id: 9002,
98 name: 'Bridget',
99 service: 'ElevenLabs',
100 model_id: 'eleven_multilingual_v2',
101 },
102 {
103 id: 9003,
104 name: 'Bridget',
105 service: 'ElevenLabs',
106 model_id: 'eleven_v3',
107 },
108 { id: 3555, name: 'Ada (Multilingual)' },
109 ];
110
111 it( 'lists the default model first, then the rest, Standard last', () => {
112 expect( getLanguageModels( voices ).map( ( m ) => m.key ) ).toEqual( [
113 'eleven_multilingual_v2',
114 'eleven_flash_v2_5',
115 'eleven_v3',
116 STANDARD_MODEL_KEY,
117 ] );
118 } );
119
120 it( 'labels each model bucket', () => {
121 expect( getLanguageModels( voices ).map( ( m ) => m.label ) ).toEqual( [
122 'Multilingual v2',
123 'Flash v2.5',
124 'v3',
125 'Legacy',
126 ] );
127 } );
128
129 it( 'omits the Standard bucket when no non-ElevenLabs voices exist', () => {
130 expect(
131 getLanguageModels( voices.slice( 0, 3 ) ).map( ( m ) => m.key )
132 ).toEqual( [
133 'eleven_multilingual_v2',
134 'eleven_flash_v2_5',
135 'eleven_v3',
136 ] );
137 } );
138
139 it( 'returns a single Standard bucket for non-ElevenLabs voices only', () => {
140 expect( getLanguageModels( [ { id: 1, name: 'Ada' } ] ) ).toEqual( [
141 { key: STANDARD_MODEL_KEY, label: 'Legacy' },
142 ] );
143 } );
144
145 it( 'handles an empty or missing voices list', () => {
146 expect( getLanguageModels( [] ) ).toEqual( [] );
147 expect( getLanguageModels( undefined ) ).toEqual( [] );
148 } );
149 } );
150
151 describe( 'source/output predicates', () => {
152 it( 'normalizeSource maps the removed script-only value to Post + script', () => {
153 expect( normalizeSource( LEGACY_SOURCE_SCRIPT ) ).toBe(
154 SOURCE_POST_AND_SCRIPT
155 );
156 expect( normalizeSource( SOURCE_POST_AND_SCRIPT ) ).toBe(
157 SOURCE_POST_AND_SCRIPT
158 );
159 } );
160
161 it( 'normalizeSource falls back to Post for unset and unknown values', () => {
162 expect( normalizeSource( SOURCE_POST ) ).toBe( SOURCE_POST );
163 expect( normalizeSource( '' ) ).toBe( SOURCE_POST );
164 expect( normalizeSource( undefined ) ).toBe( SOURCE_POST );
165 expect( normalizeSource( 'not-a-real-source' ) ).toBe( SOURCE_POST );
166 } );
167
168 it( 'sourceIncludesScript', () => {
169 expect( sourceIncludesScript( SOURCE_POST_AND_SCRIPT ) ).toBe( true );
170 expect( sourceIncludesScript( LEGACY_SOURCE_SCRIPT ) ).toBe( true );
171 expect( sourceIncludesScript( SOURCE_POST ) ).toBe( false );
172 } );
173
174 it( 'outputIncludesAudio', () => {
175 expect( outputIncludesAudio( OUTPUT_AUDIO ) ).toBe( true );
176 expect( outputIncludesAudio( OUTPUT_AUDIO_AND_VIDEO ) ).toBe( true );
177 expect( outputIncludesAudio( OUTPUT_VIDEO ) ).toBe( false );
178 } );
179
180 it( 'outputIncludesVideo', () => {
181 expect( outputIncludesVideo( OUTPUT_VIDEO ) ).toBe( true );
182 expect( outputIncludesVideo( OUTPUT_AUDIO_AND_VIDEO ) ).toBe( true );
183 expect( outputIncludesVideo( OUTPUT_AUDIO ) ).toBe( false );
184 } );
185
186 it( 'getSourceOptions / getOutputOptions expose the expected values', () => {
187 expect( getSourceOptions().map( ( o ) => o.value ) ).toEqual( [
188 SOURCE_POST,
189 SOURCE_POST_AND_SCRIPT,
190 ] );
191 expect( getOutputOptions().map( ( o ) => o.value ) ).toEqual( [
192 OUTPUT_AUDIO,
193 OUTPUT_VIDEO,
194 OUTPUT_AUDIO_AND_VIDEO,
195 ] );
196 } );
197 } );
198
199 describe( 'getEmbedOptions', () => {
200 const values = ( source, output ) =>
201 getEmbedOptions( source, output ).map( ( o ) => o.value );
202
203 it( 'Post + Audio → None / Audio (post)', () => {
204 expect( values( SOURCE_POST, OUTPUT_AUDIO ) ).toEqual( [
205 EMBED_NONE,
206 EMBED_AUDIO_POST,
207 ] );
208 } );
209
210 it( 'Post + Script × Audio + Video → all four assets', () => {
211 expect(
212 values( SOURCE_POST_AND_SCRIPT, OUTPUT_AUDIO_AND_VIDEO )
213 ).toEqual( [
214 EMBED_NONE,
215 EMBED_AUDIO_POST,
216 EMBED_AUDIO_SCRIPT,
217 EMBED_VIDEO_POST,
218 EMBED_VIDEO_SCRIPT,
219 ] );
220 } );
221
222 it( 'Post + script + Video → None / Video (post) / Video (script)', () => {
223 expect( values( SOURCE_POST_AND_SCRIPT, OUTPUT_VIDEO ) ).toEqual( [
224 EMBED_NONE,
225 EMBED_VIDEO_POST,
226 EMBED_VIDEO_SCRIPT,
227 ] );
228 } );
229
230 // Those posts have the post assets too, so hiding them was the v7 bug.
231 it( 'the removed script-only value derives the Post + script options', () => {
232 expect( values( LEGACY_SOURCE_SCRIPT, OUTPUT_AUDIO ) ).toEqual(
233 values( SOURCE_POST_AND_SCRIPT, OUTPUT_AUDIO )
234 );
235 } );
236
237 it( 'always includes None first', () => {
238 expect( values( SOURCE_POST, OUTPUT_AUDIO )[ 0 ] ).toBe( EMBED_NONE );
239 } );
240 } );
241
242 describe( 'isEmbedValid', () => {
243 it( 'accepts an asset the source/output produces', () => {
244 expect(
245 isEmbedValid( EMBED_AUDIO_POST, SOURCE_POST, OUTPUT_AUDIO )
246 ).toBe( true );
247 } );
248
249 it( 'rejects an asset the source/output cannot produce', () => {
250 expect(
251 isEmbedValid( EMBED_VIDEO_SCRIPT, SOURCE_POST, OUTPUT_AUDIO )
252 ).toBe( false );
253 } );
254
255 it( 'always accepts None', () => {
256 expect( isEmbedValid( EMBED_NONE, SOURCE_POST, OUTPUT_AUDIO ) ).toBe(
257 true
258 );
259 } );
260 } );
261
262 describe( 'getDefaultEmbed', () => {
263 it( 'returns the first asset for Post + Audio', () => {
264 expect( getDefaultEmbed( SOURCE_POST, OUTPUT_AUDIO ) ).toBe(
265 EMBED_AUDIO_POST
266 );
267 } );
268
269 it( 'returns the first video asset for Post + Video', () => {
270 expect( getDefaultEmbed( SOURCE_POST, OUTPUT_VIDEO ) ).toBe(
271 EMBED_VIDEO_POST
272 );
273 } );
274
275 it( 'returns a non-None value for every source/output combination', () => {
276 [ SOURCE_POST, SOURCE_POST_AND_SCRIPT ].forEach( ( source ) => {
277 [ OUTPUT_AUDIO, OUTPUT_VIDEO, OUTPUT_AUDIO_AND_VIDEO ].forEach(
278 ( output ) => {
279 expect( getDefaultEmbed( source, output ) ).not.toBe(
280 EMBED_NONE
281 );
282 }
283 );
284 } );
285 } );
286 } );
287