import { parse } from '@babel/parser'
import { FileType, ProjectPluginStructure } from '@teleporthq/teleport-types'
import { NextCollapsibleTextProjectPlugin } from '../src/collapsible-text/project-plugin'
const APP_CONTENT = `import { GlobalProvider } from '../global-context'
const MyApp = ({ Component, pageProps }) => {
return (
)
}
export default MyApp
`
function makeStructure(): ProjectPluginStructure {
const files = new Map()
files.set('_app', {
path: ['pages'],
files: [{ name: '_app', fileType: FileType.JS, content: APP_CONTENT }],
})
return {
uidl: {
name: 'test-project',
globals: { settings: { title: 'Test', language: 'en' }, assets: [] },
root: {} as never,
},
files,
dependencies: {},
devDependencies: {},
template: { files: [], subFolders: [] },
} as unknown as ProjectPluginStructure
}
describe('NextCollapsibleTextProjectPlugin', () => {
it('emits the null-rendering overflow helper component', async () => {
const plugin = new NextCollapsibleTextProjectPlugin()
const structure = makeStructure()
await plugin.runAfter(structure)
const component = structure.files.get('tq-collapsible-text-overflow')
expect(component).toBeDefined()
expect(component.path).toEqual(['components'])
expect(component.files[0].name).toBe('tq-collapsible-text-overflow')
const src = component.files[0].content as string
// Measures the clamped view and stamps the overflow verdict on the root.
expect(src).toContain('[data-tq-collapsible-clamp]')
expect(src).toContain('scrollHeight')
expect(src).toContain('clientHeight')
expect(src).toContain("setAttribute('data-tq-overflows'")
// Ships the CSS rule that hides Show more when the text does not overflow.
expect(src).toContain('[data-tq-overflows="false"] [data-tq-collapsible-more]')
expect(src).toContain('display:none')
// Re-measures on resize + DOM changes (SPA nav, expand/collapse remounts).
expect(src).toContain("addEventListener('resize'")
expect(src).toContain('MutationObserver')
// Null-rendering React component.
expect(src).toContain('return null')
})
it('injects into _app as a fragment sibling, idempotently', async () => {
const plugin = new NextCollapsibleTextProjectPlugin()
const structure = makeStructure()
await plugin.runAfter(structure)
const appFile = structure.files.get('_app').files[0]
expect(appFile.content).toContain(
"import TqCollapsibleTextOverflow from '../components/tq-collapsible-text-overflow'"
)
expect(appFile.content).toContain('>')
expect(appFile.content).toContain('<>')
// A second run must not double-inject.
await plugin.runAfter(structure)
const occurrences = appFile.content.split('').length - 1
expect(occurrences).toBe(1)
})
it('produces a still-parseable _app after the string surgery', async () => {
const plugin = new NextCollapsibleTextProjectPlugin()
const structure = makeStructure()
await plugin.runAfter(structure)
const appFile = structure.files.get('_app').files[0]
expect(() =>
parse(appFile.content as string, {
sourceType: 'module',
plugins: ['jsx'],
})
).not.toThrow()
})
})