Skip to content

Commit a346849

Browse files
committed
test(jsx-email): add failing case for <Conditional> + <Raw> corrupting MSO <![endif]--> closer (#316)
1 parent 95983e5 commit a346849

File tree

2 files changed

+131
-0
lines changed

2 files changed

+131
-0
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// @ts-ignore
2+
import React from 'react';
3+
4+
import { render } from '../src/renderer/render.js';
5+
import { Conditional } from '../src/index.js';
6+
7+
/**
8+
* Repro for issue #316: MSO conditional closer is malformed in body content.
9+
*
10+
* This test mirrors the structure reported by the user:
11+
* - a modern-clients block wrapped in <Conditional mso={false}>
12+
* - followed by an MSO-only block wrapped in <Conditional mso>
13+
* both as siblings within table rows/cells.
14+
*
15+
* Expected: the MSO block closes with `<![endif]-->` and no extra hyphens.
16+
*/
17+
describe('<Conditional> closer integrity', async () => {
18+
beforeEach(() => {
19+
vi.restoreAllMocks();
20+
vi.resetModules();
21+
});
22+
23+
it('emits a well-formed <![endif]--> for mso blocks placed in table cells', async () => {
24+
const fragment = (
25+
<table role="presentation" cellPadding={0} cellSpacing={0} width={300}>
26+
<tbody>
27+
<tr>
28+
<td>
29+
<Conditional mso={false}>
30+
<table data-test="modern" role="presentation" width={300}>
31+
<tbody>
32+
<tr>
33+
<td>modern</td>
34+
</tr>
35+
</tbody>
36+
</table>
37+
</Conditional>
38+
</td>
39+
</tr>
40+
<tr>
41+
<td>
42+
<Conditional mso>
43+
<table data-test="mso" role="presentation" width={300}>
44+
<tbody>
45+
<tr>
46+
<td>mso</td>
47+
</tr>
48+
</tbody>
49+
</table>
50+
</Conditional>
51+
</td>
52+
</tr>
53+
</tbody>
54+
</table>
55+
);
56+
57+
const html = await render(fragment, { pretty: true });
58+
59+
// Guard against the known-bad tail observed in .eml outputs:
60+
expect(html).not.toContain('<!--[endif]---->');
61+
62+
// Verify that our MSO block uses a valid closer.
63+
// We limit the search to our block by anchoring on a unique attribute.
64+
const start = html.indexOf('<!--[if mso]');
65+
const msoIdx = html.indexOf('data-test="mso"', start);
66+
expect(start).toBeGreaterThan(-1);
67+
expect(msoIdx).toBeGreaterThan(-1);
68+
69+
// small window around our block
70+
const tail = html.slice(msoIdx, msoIdx + 400);
71+
expect(tail).toContain('<![endif]-->');
72+
});
73+
});
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// @ts-ignore
2+
import React from 'react';
3+
4+
import { render } from '../src/renderer/render.js';
5+
import { Conditional, Raw } from '../src/index.js';
6+
7+
describe('<Conditional> + <Raw> interaction', async () => {
8+
beforeEach(() => {
9+
vi.restoreAllMocks();
10+
vi.resetModules();
11+
});
12+
13+
it('does not corrupt the <![endif]--> closer when Raw is present inside the MSO block', async () => {
14+
const fragment = (
15+
<table role="presentation" cellPadding={0} cellSpacing={0} width={300}>
16+
<tbody>
17+
<tr>
18+
<td>
19+
<Conditional mso>
20+
<table role="presentation" width={300}>
21+
<tbody>
22+
<tr>
23+
<td style={{ fontSize: 0, height: 16, width: 16 }}>
24+
{/* Minimal VML corner via Raw (no comments inside) */}
25+
<Raw
26+
content={
27+
'<v:shape style="display:block;position:relative;width:16px;height:16px" coordorigin="0 0" coordsize="2 2" fillcolor="#def2f4" fill="true" stroke="f" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word"><v:path v="m 0,2 c 0,1,1,0,2,0 l 2,2 x"/></v:shape>'
28+
}
29+
/>
30+
</td>
31+
<td style={{ fontSize: 0, height: 16 }} />
32+
<td style={{ fontSize: 0, height: 16, width: 16 }}>
33+
<Raw
34+
content={
35+
'<v:shape style="display:block;position:relative;width:16px;height:16px" coordorigin="0 0" coordsize="2 2" fillcolor="#def2f4" fill="true" stroke="f" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w="urn:schemas-microsoft-com:office:word"><v:path v="m 0,0 c 1,0,2,1,2,2 l 0,2 x"/></v:shape>'
36+
}
37+
/>
38+
</td>
39+
</tr>
40+
</tbody>
41+
</table>
42+
</Conditional>
43+
</td>
44+
</tr>
45+
</tbody>
46+
</table>
47+
);
48+
49+
const html = await render(fragment, { pretty: true });
50+
51+
// Known-bad form observed in issue reports
52+
expect(html).not.toContain('<!--[endif]---->');
53+
54+
// Valid closer must exist for the MSO block
55+
const idx = html.indexOf('<![endif]-->', html.indexOf('<!--[if mso]'));
56+
expect(idx).toBeGreaterThan(-1);
57+
});
58+
});

0 commit comments

Comments
 (0)