@@ -9,11 +9,16 @@ import { describe, it, expect } from 'vitest';
99import {
1010 CREDIT_CATEGORIES ,
1111 CONTRIBUTION_LEVELS ,
12+ CREDIT_ROLE_ENUM ,
13+ CREDIT_ROLE_ENUM_REVERSE ,
1214 parseAssetNames ,
1315 extractAuthors ,
1416 initMatrix ,
1517 formatAuthorForLatex ,
1618 generateLatex ,
19+ toEndpointPayload ,
20+ fromEndpointPayload ,
21+ rowsToWidgetAuthors ,
1722} from '../contributions/view.js' ;
1823
1924// ---------------------------------------------------------------------------
@@ -248,18 +253,18 @@ describe('generateLatex', () => {
248253 const rows = initMatrix ( [ 'Alice Smith' ] ) ;
249254 // All None by default → all zeros
250255 const tex = generateLatex ( rows ) ;
251- expect ( tex ) . toContain ( '{0,0,0,0,0,0,0,0,0}' ) ;
256+ expect ( tex ) . toContain ( '{0,0,0,0,0,0,0,0,0,0,0,0,0,0 }' ) ;
252257 } ) ;
253258
254- it ( 'uses \\lo for Low contributions' , ( ) => {
259+ it ( 'uses \\lo for Supporting contributions' , ( ) => {
255260 const rows = initMatrix ( [ 'Alice Smith' ] ) ;
256- rows [ 0 ] [ 'Conceptualization' ] = 'Low ' ;
261+ rows [ 0 ] [ 'Conceptualization' ] = 'Supporting ' ;
257262 expect ( generateLatex ( rows ) ) . toContain ( '\\lo' ) ;
258263 } ) ;
259264
260- it ( 'uses \\hi for High contributions' , ( ) => {
265+ it ( 'uses \\hi for Lead contributions' , ( ) => {
261266 const rows = initMatrix ( [ 'Alice Smith' ] ) ;
262- rows [ 0 ] [ 'Conceptualization' ] = 'High ' ;
267+ rows [ 0 ] [ 'Conceptualization' ] = 'Lead ' ;
263268 expect ( generateLatex ( rows ) ) . toContain ( '\\hi' ) ;
264269 } ) ;
265270
@@ -273,18 +278,141 @@ describe('generateLatex', () => {
273278// ---------------------------------------------------------------------------
274279
275280describe ( 'CREDIT_CATEGORIES' , ( ) => {
276- it ( 'has 9 entries' , ( ) => {
277- expect ( CREDIT_CATEGORIES ) . toHaveLength ( 9 ) ;
281+ it ( 'has 14 entries' , ( ) => {
282+ expect ( CREDIT_CATEGORIES ) . toHaveLength ( 14 ) ;
278283 } ) ;
279284
280- it ( 'includes Conceptualization and Funding acquisition ' , ( ) => {
285+ it ( 'includes Conceptualization and Funding Acquisition ' , ( ) => {
281286 expect ( CREDIT_CATEGORIES ) . toContain ( 'Conceptualization' ) ;
282- expect ( CREDIT_CATEGORIES ) . toContain ( 'Funding acquisition ' ) ;
287+ expect ( CREDIT_CATEGORIES ) . toContain ( 'Funding Acquisition ' ) ;
283288 } ) ;
284289} ) ;
285290
286291describe ( 'CONTRIBUTION_LEVELS' , ( ) => {
287- it ( 'contains None, Low, High in that order' , ( ) => {
288- expect ( CONTRIBUTION_LEVELS ) . toEqual ( [ 'None' , 'Low' , 'High' ] ) ;
292+ it ( 'contains None, Supporting, Equal, Lead in that order' , ( ) => {
293+ expect ( CONTRIBUTION_LEVELS ) . toEqual ( [ 'None' , 'Supporting' , 'Equal' , 'Lead' ] ) ;
294+ } ) ;
295+ } ) ;
296+
297+ // ---------------------------------------------------------------------------
298+ // CREDIT_ROLE_ENUM / CREDIT_ROLE_ENUM_REVERSE
299+ // ---------------------------------------------------------------------------
300+
301+ describe ( 'CREDIT_ROLE_ENUM' , ( ) => {
302+ it ( 'maps every CREDIT_CATEGORIES entry to a kebab-case string' , ( ) => {
303+ for ( const cat of CREDIT_CATEGORIES ) {
304+ expect ( typeof CREDIT_ROLE_ENUM [ cat ] ) . toBe ( 'string' ) ;
305+ expect ( CREDIT_ROLE_ENUM [ cat ] ) . toMatch ( / ^ [ a - z - ] + $ / ) ;
306+ }
307+ } ) ;
308+
309+ it ( 'maps Conceptualization to conceptualization' , ( ) => {
310+ expect ( CREDIT_ROLE_ENUM [ 'Conceptualization' ] ) . toBe ( 'conceptualization' ) ;
311+ } ) ;
312+ } ) ;
313+
314+ describe ( 'CREDIT_ROLE_ENUM_REVERSE' , ( ) => {
315+ it ( 'is a proper inverse of CREDIT_ROLE_ENUM' , ( ) => {
316+ for ( const [ display , enumVal ] of Object . entries ( CREDIT_ROLE_ENUM ) ) {
317+ expect ( CREDIT_ROLE_ENUM_REVERSE [ enumVal ] ) . toBe ( display ) ;
318+ }
319+ } ) ;
320+ } ) ;
321+
322+ // ---------------------------------------------------------------------------
323+ // toEndpointPayload
324+ // ---------------------------------------------------------------------------
325+
326+ describe ( 'toEndpointPayload' , ( ) => {
327+ it ( 'sets project_name correctly' , ( ) => {
328+ const rows = initMatrix ( [ 'Alice Smith' ] ) ;
329+ const payload = toEndpointPayload ( rows , 'my-project' ) ;
330+ expect ( payload . project_name ) . toBe ( 'my-project' ) ;
331+ } ) ;
332+
333+ it ( 'omits None contributions from credit_levels' , ( ) => {
334+ const rows = initMatrix ( [ 'Alice Smith' ] ) ;
335+ // All None by default
336+ const payload = toEndpointPayload ( rows , 'proj' ) ;
337+ expect ( payload . contributors [ 0 ] . credit_levels ) . toHaveLength ( 0 ) ;
338+ } ) ;
339+
340+ it ( 'includes non-None contributions with kebab-case role and lowercase level' , ( ) => {
341+ const rows = initMatrix ( [ 'Alice Smith' ] ) ;
342+ rows [ 0 ] [ 'Conceptualization' ] = 'Lead' ;
343+ rows [ 0 ] [ 'Software' ] = 'Supporting' ;
344+ const payload = toEndpointPayload ( rows , 'proj' ) ;
345+ const levels = payload . contributors [ 0 ] . credit_levels ;
346+ expect ( levels ) . toContainEqual ( { role : 'conceptualization' , level : 'lead' } ) ;
347+ expect ( levels ) . toContainEqual ( { role : 'software' , level : 'supporting' } ) ;
348+ } ) ;
349+
350+ it ( 'includes person.name for each contributor' , ( ) => {
351+ const rows = initMatrix ( [ 'Bob Jones' ] ) ;
352+ const payload = toEndpointPayload ( rows , 'proj' ) ;
353+ expect ( payload . contributors [ 0 ] . person . name ) . toBe ( 'Bob Jones' ) ;
354+ } ) ;
355+ } ) ;
356+
357+ // ---------------------------------------------------------------------------
358+ // fromEndpointPayload
359+ // ---------------------------------------------------------------------------
360+
361+ describe ( 'fromEndpointPayload' , ( ) => {
362+ it ( 'converts endpoint payload back into matrix rows' , ( ) => {
363+ const data = {
364+ project_name : 'proj' ,
365+ contributors : [
366+ {
367+ person : { name : 'Alice Smith' } ,
368+ credit_levels : [
369+ { role : 'conceptualization' , level : 'lead' } ,
370+ { role : 'software' , level : 'supporting' } ,
371+ ] ,
372+ } ,
373+ ] ,
374+ } ;
375+ const rows = fromEndpointPayload ( data ) ;
376+ expect ( rows ) . toHaveLength ( 1 ) ;
377+ expect ( rows [ 0 ] . name ) . toBe ( 'Alice Smith' ) ;
378+ expect ( rows [ 0 ] [ 'Conceptualization' ] ) . toBe ( 'Lead' ) ;
379+ expect ( rows [ 0 ] [ 'Software' ] ) . toBe ( 'Supporting' ) ;
380+ expect ( rows [ 0 ] [ 'Methodology' ] ) . toBe ( 'None' ) ;
381+ } ) ;
382+
383+ it ( 'returns empty array for empty contributors' , ( ) => {
384+ expect ( fromEndpointPayload ( { project_name : 'p' , contributors : [ ] } ) ) . toEqual ( [ ] ) ;
385+ } ) ;
386+
387+ it ( 'round-trips through toEndpointPayload → fromEndpointPayload' , ( ) => {
388+ const original = initMatrix ( [ 'Alice Smith' , 'Bob Jones' ] ) ;
389+ original [ 0 ] [ 'Conceptualization' ] = 'Lead' ;
390+ original [ 1 ] [ 'Software' ] = 'Equal' ;
391+ const payload = toEndpointPayload ( original , 'proj' ) ;
392+ const restored = fromEndpointPayload ( payload ) ;
393+ expect ( restored [ 0 ] [ 'Conceptualization' ] ) . toBe ( 'Lead' ) ;
394+ expect ( restored [ 1 ] [ 'Software' ] ) . toBe ( 'Equal' ) ;
395+ expect ( restored [ 0 ] [ 'Software' ] ) . toBe ( 'None' ) ;
396+ } ) ;
397+ } ) ;
398+
399+ // ---------------------------------------------------------------------------
400+ // rowsToWidgetAuthors
401+ // ---------------------------------------------------------------------------
402+
403+ describe ( 'rowsToWidgetAuthors' , ( ) => {
404+ it ( 'converts rows to widget author format with display role names' , ( ) => {
405+ const rows = initMatrix ( [ 'Alice Smith' ] ) ;
406+ rows [ 0 ] [ 'Conceptualization' ] = 'Lead' ;
407+ const authors = rowsToWidgetAuthors ( rows ) ;
408+ expect ( authors [ 0 ] . name ) . toBe ( 'Alice Smith' ) ;
409+ expect ( authors [ 0 ] . credit_levels ) . toContainEqual ( { role : 'Conceptualization' , level : 'lead' } ) ;
410+ } ) ;
411+
412+ it ( 'omits None levels from credit_levels' , ( ) => {
413+ const rows = initMatrix ( [ 'Bob Jones' ] ) ;
414+ // All None
415+ const authors = rowsToWidgetAuthors ( rows ) ;
416+ expect ( authors [ 0 ] . credit_levels ) . toHaveLength ( 0 ) ;
289417 } ) ;
290418} ) ;
0 commit comments