import { describe, beforeAll, beforeEach, it, expect } from 'vitest'; import parseFixture from '../__fixtures__/parse-fixture'; import addText from './add-text'; describe('add-text', () => { let realisticAST, mockAST, withSubSectionAST, withNestedInstructionsAST, withChineseAST, withEnUsAST, withEsAST; const descriptionId = 'description'; const instructionsId = 'instructions'; const missingId = 'missing'; let file = { data: {} }; beforeAll(async () => { realisticAST = await parseFixture('realistic.md'); mockAST = await parseFixture('simple.md'); withSubSectionAST = await parseFixture('with-subsection.md'); withNestedInstructionsAST = await parseFixture( 'with-nested-instructions.md' ); withChineseAST = await parseFixture('with-chinese-mcq.md'); withEnUsAST = await parseFixture('with-en-us-mcq.md'); withEsAST = await parseFixture('with-es-mcq.md'); }); beforeEach(() => { file = { data: {} }; }); it('should return a function', () => { const plugin = addText(['section']); expect(typeof plugin).toEqual('function'); }); it('throws when no argument or the incorrect argument is supplied', () => { expect.assertions(5); const expectedError = 'addText must have an array of section ids supplied'; expect(() => { addText(); }).toThrow(expectedError); expect(() => { addText(''); }).toThrow(expectedError); expect(() => { addText({}); }).toThrow(expectedError); expect(() => { addText(1); }).toThrow(expectedError); expect(() => { addText([]); }).toThrow(expectedError); }); it('throws when there is a sub-section in one of the sections', () => { const plugin = addText([instructionsId, descriptionId]); expect(() => { plugin(withSubSectionAST, file); }).toThrow( 'The --description-- section should not have any subsections. Found subsection --not-allowed--' ); }); it('should add a string relating to the section id to `file.data`', () => { const plugin = addText([descriptionId]); plugin(mockAST, file); const expectedText = 'Paragraph 1'; expect(file.data[descriptionId]).toEqual( expect.stringContaining(expectedText) ); }); it('should not add a string relating a different id to `file.data`', () => { const plugin = addText([descriptionId]); plugin(mockAST, file); // the following text is in the AST, but is associated with a different // marker (instructions) const expectedText = 'Paragraph 0'; expect(file.data[descriptionId]).not.toEqual( expect.stringContaining(expectedText) ); }); // TODO: do we need to add the ids to the section tags? Why not just have //
? it('should embed the text in sections with appropriate ids', () => { const plugin = addText([descriptionId, instructionsId]); plugin(mockAST, file); // the following text is in the AST, but is associated with a different // marker (instructions) const descriptionSectionText = `

Paragraph 1

code example
`; expect(file.data[descriptionId]).toEqual(descriptionSectionText); const instructionsSectionText = `

Paragraph 0

code example 0
`; expect(file.data[instructionsId]).toBe(instructionsSectionText); }); it('should add nothing if a section id does not appear in the md', () => { const plugin = addText([missingId]); plugin(mockAST, file); expect(file.data[descriptionId]).toBeUndefined(); }); it('should not escape html', () => { const plugin = addText([descriptionId]); plugin(realisticAST, file); const expected = `last h2 element`; expect(file.data[descriptionId]).toEqual(expect.stringContaining(expected)); }); it('should preserve nested html', () => { const plugin = addText([descriptionId]); plugin(realisticAST, file); const expected = `

Some text in a blockquote

Some text in a blockquote, with code

`; expect(file.data[descriptionId]).toEqual(expect.stringContaining(expected)); }); it('should not add paragraphs when html elements are separated by whitespace', () => { const plugin = addText([instructionsId]); plugin(realisticAST, file); const expectedText1 = `code with more after a space`; const expectedText2 = `another pair of elements with a space`; expect(file.data[instructionsId]).toEqual( expect.stringContaining(expectedText1) ); expect(file.data[instructionsId]).toEqual( expect.stringContaining(expectedText2) ); }); it('should ignore --instructions-- markers that are not at depth 1', () => { const plugin = addText([instructionsId]); plugin(withNestedInstructionsAST, file); // Should only include the depth 1 instructions, not the nested ones const expectedText = `

These are the main instructions at depth 1.

<div>Main instructions code</div>
`; expect(file.data[instructionsId]).toEqual(expectedText); }); it('should have an output to match the snapshot', () => { const plugin = addText([descriptionId, instructionsId]); plugin(mockAST, file); expect(file.data).toMatchSnapshot(); }); it('should render inline code as code elements when lang is undefined', () => { const plugin = addText(['instructions', 'explanation']); const defaultFile = { data: {} }; plugin(withChineseAST, defaultFile); expect(defaultFile.data.instructions).toBe( '
\n

Instructions containing 汉字 (hàn zì).

\n
' ); expect(defaultFile.data.explanation).toBe( '
\n

我是 (wǒ shì) Web 开发者 (kāi fā zhě)。 – I am a web developer.

\n

你好 (nǐ hǎo),我是王华 (wǒ shì Wang Hua),请问你叫什么名字 (qǐng wèn nǐ jiào shén me míng zi)? – Hello, I am Wang Hua, may I ask what your name is?

\n
' ); }); it('should render Chinese inline code as ruby when lang is zh-CN', () => { const plugin = addText(['instructions', 'explanation']); const zhFile = { data: { lang: 'zh-CN' } }; plugin(withChineseAST, zhFile); expect(zhFile.data.instructions).toBe( '
\n

Instructions containing 汉字(hàn zì).

\n
' ); expect(zhFile.data.explanation).toBe( '
\n

我是(wǒ shì) Web 开发者(kāi fā zhě)。 – I am a web developer.

\n

你好(nǐ hǎo)我是王华(wǒ shì Wang Hua)请问你叫什么名字(qǐng wèn nǐ jiào shén me míng zi)? – Hello, I am Wang Hua, may I ask what your name is?

\n
' ); }); it('should render inline code as span elements when lang is en-US', () => { const plugin = addText(['instructions', 'explanation']); const enUsFile = { data: { lang: 'en-US' } }; plugin(withEnUsAST, enUsFile); expect(enUsFile.data.instructions).toBe( '
\n

Instructions containing some code.

\n
' ); expect(enUsFile.data.explanation).toBe( '
\n

Explanation text containing highlighted text.

\n
' ); }); it('should render inline code as span elements when lang is es', () => { const plugin = addText(['instructions', 'explanation']); const esFile = { data: { lang: 'es' } }; plugin(withEsAST, esFile); expect(esFile.data.instructions).toBe( '
\n

Instructions containing texto resaltado.

\n
' ); expect(esFile.data.explanation).toBe( '
\n

Explanation text containing texto resaltado.

\n
' ); }); });