Skip to content

Commit 0e32ba8

Browse files
Merge test coverage from PR #45
Added comprehensive test suites for core transformation functions: - convert-deepnote-block-to-jupyter-cell.spec.ts (13 tests) - transform-deepnote-yaml-to-notebook-content.spec.ts (11 tests) Overall coverage improved from 31.03% to 57.24% Both transformation files now have 100% line coverage
1 parent 9e2eda0 commit 0e32ba8

File tree

2 files changed

+633
-0
lines changed

2 files changed

+633
-0
lines changed
Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
// Copyright (c) Deepnote
2+
// Distributed under the terms of the Modified BSD License.
3+
4+
import { convertDeepnoteBlockToJupyterCell } from '../convert-deepnote-block-to-jupyter-cell';
5+
import { DeepnoteBlock } from '@deepnote/blocks';
6+
7+
jest.mock('@deepnote/blocks', () => ({
8+
createPythonCode: jest.fn((block: any) => block.source || 'print("test")'),
9+
createMarkdown: jest.fn((block: any) => block.source || '# Test')
10+
}));
11+
12+
jest.mock('../convert-deepnote-block-type-to-jupyter', () => ({
13+
convertDeepnoteBlockTypeToJupyter: jest.fn((type: string) => {
14+
if (
15+
[
16+
'code',
17+
'sql',
18+
'notebook-function',
19+
'big-number',
20+
'visualization',
21+
'input-text',
22+
'input-checkbox',
23+
'input-textarea',
24+
'input-file',
25+
'input-select',
26+
'input-date-range',
27+
'input-date',
28+
'input-slider'
29+
].includes(type)
30+
) {
31+
return 'code';
32+
}
33+
return 'markdown';
34+
})
35+
}));
36+
37+
describe('convertDeepnoteBlockToJupyterCell', () => {
38+
describe('code cells', () => {
39+
it('should convert a basic code block to a Jupyter code cell', () => {
40+
const block: DeepnoteBlock = {
41+
id: 'block-1',
42+
type: 'code',
43+
source: 'print("hello")',
44+
metadata: { foo: 'bar' }
45+
} as any;
46+
47+
const result = convertDeepnoteBlockToJupyterCell(block);
48+
49+
expect(result.cell_type).toBe('code');
50+
expect(result.metadata).toEqual({ foo: 'bar', cell_id: 'block-1' });
51+
expect(result.source).toBe('print("hello")');
52+
expect(result.execution_count).toBeNull();
53+
expect(result.outputs).toEqual([]);
54+
55+
const { createPythonCode } = jest.requireMock('@deepnote/blocks');
56+
expect(createPythonCode).toHaveBeenCalledTimes(1);
57+
expect(createPythonCode).toHaveBeenCalledWith(
58+
expect.objectContaining({ id: 'block-1' })
59+
);
60+
});
61+
62+
it('should include execution count if present', () => {
63+
const block: DeepnoteBlock = {
64+
id: 'block-2',
65+
type: 'code',
66+
source: 'x = 1',
67+
metadata: {},
68+
executionCount: 5
69+
} as any;
70+
71+
const result = convertDeepnoteBlockToJupyterCell(block);
72+
73+
expect(result.cell_type).toBe('code');
74+
expect(result.execution_count).toBe(5);
75+
});
76+
77+
it('should include outputs if present', () => {
78+
const blockOutputs = [
79+
{
80+
output_type: 'stream',
81+
name: 'stdout',
82+
text: 'hello\n'
83+
}
84+
];
85+
86+
const block: DeepnoteBlock = {
87+
id: 'block-3',
88+
type: 'code',
89+
source: 'print("hello")',
90+
metadata: {},
91+
outputs: blockOutputs
92+
} as any;
93+
94+
const result = convertDeepnoteBlockToJupyterCell(block);
95+
96+
expect(result.cell_type).toBe('code');
97+
expect(result.outputs).toEqual(blockOutputs);
98+
});
99+
100+
it('should remove truncated property from outputs', () => {
101+
const blockOutputs = [
102+
{
103+
output_type: 'stream',
104+
name: 'stdout',
105+
text: 'hello\n',
106+
truncated: true
107+
}
108+
];
109+
110+
const block: DeepnoteBlock = {
111+
id: 'block-4',
112+
type: 'code',
113+
source: 'print("hello")',
114+
metadata: {},
115+
outputs: blockOutputs
116+
} as any;
117+
118+
const result = convertDeepnoteBlockToJupyterCell(block);
119+
120+
expect(result.cell_type).toBe('code');
121+
expect(result.outputs).toHaveLength(1);
122+
const resultOutputs = result.outputs as any[];
123+
expect(resultOutputs[0]).not.toHaveProperty('truncated');
124+
expect(resultOutputs[0]).toEqual({
125+
output_type: 'stream',
126+
name: 'stdout',
127+
text: 'hello\n'
128+
});
129+
});
130+
131+
it('should handle multiple outputs with truncated properties', () => {
132+
const blockOutputs = [
133+
{
134+
output_type: 'stream',
135+
name: 'stdout',
136+
text: 'line1\n',
137+
truncated: true
138+
},
139+
{
140+
output_type: 'stream',
141+
name: 'stdout',
142+
text: 'line2\n',
143+
truncated: false
144+
}
145+
];
146+
147+
const block: DeepnoteBlock = {
148+
id: 'block-5',
149+
type: 'code',
150+
source: 'print("test")',
151+
metadata: {},
152+
outputs: blockOutputs
153+
} as any;
154+
155+
const result = convertDeepnoteBlockToJupyterCell(block);
156+
157+
expect(result.cell_type).toBe('code');
158+
expect(result.outputs).toHaveLength(2);
159+
const resultOutputs = result.outputs as any[];
160+
expect(resultOutputs[0]).not.toHaveProperty('truncated');
161+
expect(resultOutputs[1]).not.toHaveProperty('truncated');
162+
});
163+
164+
it('should not mutate the original block', () => {
165+
const blockOutputs = [
166+
{
167+
output_type: 'stream',
168+
name: 'stdout',
169+
text: 'hello\n',
170+
truncated: true
171+
}
172+
];
173+
174+
const block: DeepnoteBlock = {
175+
id: 'block-6',
176+
type: 'code',
177+
source: 'print("hello")',
178+
metadata: { test: 'value' },
179+
outputs: blockOutputs
180+
} as any;
181+
182+
convertDeepnoteBlockToJupyterCell(block);
183+
184+
expect(block.outputs![0]).toHaveProperty('truncated');
185+
expect(block.metadata).toEqual({ test: 'value' });
186+
});
187+
});
188+
189+
describe('markdown cells', () => {
190+
it('should convert a basic markdown block to a Jupyter markdown cell', () => {
191+
const block: DeepnoteBlock = {
192+
id: 'block-7',
193+
type: 'markdown',
194+
source: '# Hello',
195+
metadata: { foo: 'bar' }
196+
} as any;
197+
198+
const result = convertDeepnoteBlockToJupyterCell(block);
199+
200+
expect(result.cell_type).toBe('markdown');
201+
expect(result.metadata).toEqual({});
202+
expect(result.source).toBe('# Hello');
203+
204+
const { createMarkdown } = jest.requireMock('@deepnote/blocks');
205+
expect(createMarkdown).toHaveBeenCalledTimes(1);
206+
expect(createMarkdown).toHaveBeenCalledWith(
207+
expect.objectContaining({ id: 'block-7' })
208+
);
209+
});
210+
211+
it('should convert text-cell-h1 to markdown cell', () => {
212+
const block: DeepnoteBlock = {
213+
id: 'block-8',
214+
type: 'text-cell-h1',
215+
source: 'Heading 1',
216+
metadata: {}
217+
} as any;
218+
219+
const result = convertDeepnoteBlockToJupyterCell(block);
220+
221+
expect(result.cell_type).toBe('markdown');
222+
});
223+
224+
it('should convert image block to markdown cell', () => {
225+
const block: DeepnoteBlock = {
226+
id: 'block-9',
227+
type: 'image',
228+
source: '![alt](url)',
229+
metadata: {}
230+
} as any;
231+
232+
const result = convertDeepnoteBlockToJupyterCell(block);
233+
234+
expect(result.cell_type).toBe('markdown');
235+
});
236+
237+
it('should not include metadata from Deepnote block in markdown cells', () => {
238+
const block: DeepnoteBlock = {
239+
id: 'block-10',
240+
type: 'markdown',
241+
source: 'Text',
242+
metadata: { deepnoteMetadata: 'should not appear' }
243+
} as any;
244+
245+
const result = convertDeepnoteBlockToJupyterCell(block);
246+
247+
expect(result.cell_type).toBe('markdown');
248+
expect(result.metadata).toEqual({});
249+
});
250+
});
251+
252+
describe('special block types', () => {
253+
it('should convert sql block to code cell', () => {
254+
const block: DeepnoteBlock = {
255+
id: 'block-11',
256+
type: 'sql',
257+
source: 'SELECT * FROM table',
258+
metadata: {}
259+
} as any;
260+
261+
const result = convertDeepnoteBlockToJupyterCell(block);
262+
263+
expect(result.cell_type).toBe('code');
264+
});
265+
266+
it('should convert visualization block to code cell', () => {
267+
const block: DeepnoteBlock = {
268+
id: 'block-12',
269+
type: 'visualization',
270+
source: 'chart_data',
271+
metadata: {}
272+
} as any;
273+
274+
const result = convertDeepnoteBlockToJupyterCell(block);
275+
276+
expect(result.cell_type).toBe('code');
277+
});
278+
279+
it('should convert input blocks to code cells', () => {
280+
const inputTypes = [
281+
'input-text',
282+
'input-checkbox',
283+
'input-textarea',
284+
'input-file',
285+
'input-select',
286+
'input-date-range',
287+
'input-date',
288+
'input-slider'
289+
];
290+
291+
inputTypes.forEach(type => {
292+
const block: DeepnoteBlock = {
293+
id: `block-${type}`,
294+
type,
295+
source: 'input_value',
296+
metadata: {}
297+
} as any;
298+
299+
const result = convertDeepnoteBlockToJupyterCell(block);
300+
301+
expect(result.cell_type).toBe('code');
302+
});
303+
});
304+
});
305+
});

0 commit comments

Comments
 (0)