@@ -21,7 +21,6 @@ import assert from 'node:assert/strict';
2121
2222import {
2323 authorIdsToResolve ,
24- paragraphs ,
2524 shapeDisasters ,
2625 tellerFor ,
2726 tellersFromProfiles
@@ -43,9 +42,9 @@ const row = (over = {}) => ({
4342 ...over
4443} ) ;
4544
46- const shape = ( rows , tellers = new Map ( ) , over = { } ) => {
45+ const shape = async ( rows , tellers = new Map ( ) , over = { } ) => {
4746 const warnings = [ ] ;
48- const out = shapeDisasters ( rows , tellers , {
47+ const out = await shapeDisasters ( rows , tellers , {
4948 severityIds : SEVERITY_IDS ,
5049 likesById : new Map ( ) ,
5150 repliesById : new Map ( ) ,
@@ -119,25 +118,25 @@ test('an anonymous story asks for no profile at all', () => {
119118 assert . deepEqual ( ids , [ 'u2' ] , 'anonymous rows must not send their author id to the profiles query' ) ;
120119} ) ;
121120
122- test ( 'an unknown severity is left off the site and reported with its id' , ( ) => {
123- const { out, warnings } = shape ( [ row ( { id : 7 , severity : 'catastrophe' } ) ] ) ;
121+ test ( 'an unknown severity is left off the site and reported with its id' , async ( ) => {
122+ const { out, warnings } = await shape ( [ row ( { id : 7 , severity : 'catastrophe' } ) ] ) ;
124123
125124 assert . equal ( out . length , 0 ) ;
126125 assert . equal ( warnings . length , 1 ) ;
127126 assert . match ( warnings [ 0 ] , / D e v d i s a s t e r 7 / , 'the warning does not name the row, so nobody can find it' ) ;
128127 assert . match ( warnings [ 0 ] , / c a t a s t r o p h e / ) ;
129128} ) ;
130129
131- test ( 'an incomplete published row is left off rather than half drawn' , ( ) => {
130+ test ( 'an incomplete published row is left off rather than half drawn' , async ( ) => {
132131 for ( const missing of [ 'slug' , 'title' , 'line' , 'body' , 'published_at' ] ) {
133- const { out, warnings } = shape ( [ row ( { [ missing ] : null } ) ] ) ;
132+ const { out, warnings } = await shape ( [ row ( { [ missing ] : null } ) ] ) ;
134133 assert . equal ( out . length , 0 , `a row with no ${ missing } was drawn anyway` ) ;
135134 assert . match ( warnings [ 0 ] , / p u b l i s h e d b u t i n c o m p l e t e / ) ;
136135 }
137136} ) ;
138137
139- test ( 'one bad row does not take the rest of the wall with it' , ( ) => {
140- const { out } = shape ( [
138+ test ( 'one bad row does not take the rest of the wall with it' , async ( ) => {
139+ const { out } = await shape ( [
141140 row ( { id : 1 , slug : 'good' , published_at : '2026-07-01T00:00:00Z' } ) ,
142141 row ( { id : 2 , severity : 'nonsense' } ) ,
143142 row ( { id : 3 , slug : 'also-good' , published_at : '2026-07-02T00:00:00Z' } )
@@ -150,32 +149,27 @@ test('one bad row does not take the rest of the wall with it', () => {
150149 ) ;
151150} ) ;
152151
153- test ( 'stories come back newest first whatever order the rows arrived in' , ( ) => {
154- const { out } = shape ( [
152+ test ( 'stories come back newest first whatever order the rows arrived in' , async ( ) => {
153+ const { out } = await shape ( [
155154 row ( { id : 1 , published_at : '2026-01-01T00:00:00Z' } ) ,
156155 row ( { id : 2 , published_at : '2026-07-01T00:00:00Z' } ) ,
157156 row ( { id : 3 , published_at : '2026-03-01T00:00:00Z' } )
158157 ] ) ;
159158 assert . deepEqual ( out . map ( ( d ) => d . id ) , [ 2 , 3 , 1 ] ) ;
160159} ) ;
161160
162- test ( 'a story with no blank lines is one paragraph, not a defect' , ( ) => {
163- assert . deepEqual ( paragraphs ( 'Just the one.' ) , [ 'Just the one.' ] ) ;
164- assert . deepEqual ( paragraphs ( 'First.\n\nSecond.' ) , [ 'First.' , 'Second.' ] ) ;
165- assert . deepEqual ( paragraphs ( 'First.\n\n\n \n\nSecond.' ) , [ 'First.' , 'Second.' ] ) ;
166- assert . deepEqual ( paragraphs ( ' Padded. ' ) , [ 'Padded.' ] ) ;
167- assert . deepEqual ( paragraphs ( '' ) , [ ] , 'an empty body should be no paragraphs rather than one empty one' ) ;
161+ test ( 'a story body is rendered from markdown rather than left as plain paragraphs' , async ( ) => {
162+ const { out } = await shape ( [ row ( { body : 'One **bold** paragraph.\n\nAnd a second one.' } ) ] ) ;
163+ assert . equal ( out [ 0 ] . body , '<p>One <strong>bold</strong> paragraph.</p><p>And a second one.</p>' ) ;
168164} ) ;
169165
170- test ( 'a single newline is a line break inside a paragraph, not a new one' , ( ) => {
171- assert . deepEqual (
172- paragraphs ( 'One line.\nStill the same paragraph.' ) ,
173- [ 'One line.\nStill the same paragraph.' ]
174- ) ;
166+ test ( 'a heading in a story body is demoted the same way a heading in a comment is' , async ( ) => {
167+ const { out } = await shape ( [ row ( { body : '# Not a page title' } ) ] ) ;
168+ assert . equal ( out [ 0 ] . body , '<p><strong>Not a page title</strong></p>' ) ;
175169} ) ;
176170
177- test ( 'counts default to zero rather than undefined' , ( ) => {
178- const { out } = shape ( [ row ( { id : 42 } ) ] , new Map ( ) , {
171+ test ( 'counts default to zero rather than undefined' , async ( ) => {
172+ const { out } = await shape ( [ row ( { id : 42 } ) ] , new Map ( ) , {
179173 likesById : new Map ( [ [ '42' , 11 ] ] ) ,
180174 repliesById : new Map ( )
181175 } ) ;
@@ -184,17 +178,17 @@ test('counts default to zero rather than undefined', () => {
184178 assert . equal ( out [ 0 ] . replies , 0 , 'a story nobody has replied to must read zero, not undefined' ) ;
185179} ) ;
186180
187- test ( 'the url is built from the slug and stays under dev-disasters' , ( ) => {
181+ test ( 'the url is built from the slug and stays under dev-disasters' , async ( ) => {
188182 /*
189183 A disaster never belongs to a topic. If this ever starts reading a topic field, the
190184 whole URL scheme decision has been undone somewhere upstream.
191185 */
192- const { out } = shape ( [ row ( { slug : 'the-time-i-dropped-prod' } ) ] ) ;
186+ const { out } = await shape ( [ row ( { slug : 'the-time-i-dropped-prod' } ) ] ) ;
193187 assert . equal ( out [ 0 ] . url , '/dev-disasters/the-time-i-dropped-prod/' ) ;
194188} ) ;
195189
196- test ( 'featured_at becomes a date or null, never an invalid date' , ( ) => {
197- const { out } = shape ( [
190+ test ( 'featured_at becomes a date or null, never an invalid date' , async ( ) => {
191+ const { out } = await shape ( [
198192 row ( { id : 1 , featured_at : '2026-07-15T00:00:00Z' } ) ,
199193 row ( { id : 2 , featured_at : null , published_at : '2026-06-01T00:00:00Z' } )
200194 ] ) ;
@@ -203,8 +197,8 @@ test('featured_at becomes a date or null, never an invalid date', () => {
203197 assert . equal ( out . find ( ( d ) => d . id === 2 ) . featuredAt , null ) ;
204198} ) ;
205199
206- test ( 'an empty read produces an empty wall and no warnings' , ( ) => {
207- const { out, warnings } = shape ( [ ] ) ;
200+ test ( 'an empty read produces an empty wall and no warnings' , async ( ) => {
201+ const { out, warnings } = await shape ( [ ] ) ;
208202 assert . deepEqual ( out , [ ] ) ;
209203 assert . deepEqual ( warnings , [ ] ) ;
210204} ) ;
0 commit comments