Skip to content

Commit

Permalink
Add test for container query option
Browse files Browse the repository at this point in the history
  • Loading branch information
yhatt committed Oct 15, 2023
1 parent 4ae86da commit cc7e745
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 7 deletions.
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ module.exports = {
testEnvironment: 'node',
testRegex: '(/(test|__tests__)/(?!_).*|(\\.|/)(test|spec))\\.js$',
moduleFileExtensions: ['js', 'json', 'node'],
prettierPath: null,
}
26 changes: 21 additions & 5 deletions src/postcss/container_query.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const reservedNames = [
'unset',
]

const marpitContainerQueryPseudoMatcher = /\bsection:marpit-container-query\b/g

/**
* Marpit PostCSS container query plugin.
*
Expand Down Expand Up @@ -40,14 +42,28 @@ export const containerQuery = postcssPlugin(
.join(' ')};`
: ''

css.first.before(
`
:where(section) {
const style = `
section:marpit-container-query {
container-type: size;${containerNameDeclaration}
}
`.trim(),
)
`.trim()

if (css.first) {
css.first.before(style)
} else {
css.append(style)
}
},
)

export const postprocess = postcssPlugin(
'marpit-postcss-container-query-postprocess',
() => (css) =>
css.walkRules(marpitContainerQueryPseudoMatcher, (rule) => {
rule.selectors = rule.selectors.map((selector) =>
selector.replace(marpitContainerQueryPseudoMatcher, ':where(section)'),
)
}),
)

export default containerQuery
5 changes: 4 additions & 1 deletion src/theme_set.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import postcss from 'postcss'
import postcssPlugin from './helpers/postcss_plugin'
import postcssAdvancedBackground from './postcss/advanced_background'
import postcssContainerQuery from './postcss/container_query'
import postcssContainerQuery, {
postprocess as postcssContainerQueryPostProcess,
} from './postcss/container_query'
import postcssImportHoisting from './postcss/import/hoisting'
import postcssImportReplace from './postcss/import/replace'
import postcssImportSuppress from './postcss/import/suppress'
Expand Down Expand Up @@ -308,6 +310,7 @@ class ThemeSet {
postcssPseudoReplace(opts.containers, slideElements),
postcssRootIncreasingSpecificity,
opts.printable && postcssPrintablePostProcess,
opts.containerQuery && postcssContainerQueryPostProcess,
postcssRem,
postcssImportHoisting,
].filter((p) => p),
Expand Down
34 changes: 33 additions & 1 deletion test/marpit.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ describe('Marpit', () => {
expect(instance.options.anchor).toBe(true)
expect(instance.options.container.tag).toBe('div')
expect(instance.options.container.class).toBe('marpit')
expect(instance.options.markdown).toBe(undefined)
expect(instance.options.cssContainerQuery).toBe(false)
expect(instance.options.lang).toBeUndefined()
expect(instance.options.markdown).toBeUndefined()
expect(instance.options.printable).toBe(true)
expect(instance.options.slideContainer).toBe(false)
expect(instance.options.inlineSVG).toBe(false)
Expand Down Expand Up @@ -502,6 +504,36 @@ describe('Marpit', () => {
expect(token.attrGet('id')).toBe('custom-1')
})
})

context('with cssContainerQuery option', () => {
it('does not include container query style if cssContainerQuery was false', () => {
const { css } = new Marpit({ cssContainerQuery: false }).render('')
expect(css).not.toContain('container-type: size;')
})

it('includes container query style if cssContainerQuery was true', () => {
const { css } = new Marpit({ cssContainerQuery: true }).render('')
expect(css).toContain('container-type: size;')
})

it('includes container name style if cssContainerQuery was string', () => {
const { css } = new Marpit({ cssContainerQuery: 'test' }).render('')
expect(css).toContain('container-type: size;')
expect(css).toContain('container-name: test;')
})

it('includes space-separated container name style if cssContainerQuery was the array of strings', () => {
const { css } = new Marpit({ cssContainerQuery: ['a', 'b'] }).render('')
expect(css).toContain('container-type: size;')
expect(css).toContain('container-name: a b;')
})

it('does include container name style if cssContainerQuery was empty array', () => {
const { css } = new Marpit({ cssContainerQuery: [] }).render('')
expect(css).toContain('container-type: size;')
expect(css).not.toContain('container-name')
})
})
})

describe('#renderMarkdown', () => {
Expand Down
82 changes: 82 additions & 0 deletions test/postcss/container_query.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import postcss from 'postcss'
import { containerQuery, postprocess } from '../../src/postcss/container_query'
import { findDecl, findRule } from '../_supports/postcss_finder'

describe('Marpit PostCSS container query plugin', () => {
const run = (input, args = []) =>
postcss([containerQuery(...args), postprocess]).process(input, {
from: undefined,
})

it('prepends style for container query', async () => {
const css = await run('section { width: 1280px; height: 960px; }')

expect(css.css).toMatchInlineSnapshot(`
":where(section) {
container-type: size;
}
section { width: 1280px; height: 960px; }"
`)
})

context('with container name', () => {
const findContainerNameDecl = (node) => {
const rule = findRule(node, {
selector: (selector) => selector.includes('section'),
})

return findDecl(rule, { prop: 'container-name' })
}

it('prepends style for container query with name', async () => {
const { root } = await run('', ['marpit'])

expect(findContainerNameDecl(root).value).toBe('marpit')
})

it('escapes container name', async () => {
const { root } = await run('', ['123 test'])

expect(findContainerNameDecl(root).value).toBe('\\31 23\\ test')
})

it('does not assign name if the name is empty', async () => {
const { root } = await run('', [''])

expect(findContainerNameDecl(root)).toBeFalsy()
})

it('does not assign name if the name has a reserved value', async () => {
for (const name of [
'none',
'inherit',
'initial',
'revert',
'revert-layer',
'unset',
]) {
const { root } = await run('', [name])

expect(findContainerNameDecl(root)).toBeFalsy()
}
})

it('allows multiple names by passing array of strings', async () => {
const { root } = await run('', [['a', 'b', 'c']])

expect(findContainerNameDecl(root).value).toBe('a b c')
})

it('skips invalid name in array of strings', async () => {
const { root } = await run('', [['test', '', 'test2']])

expect(findContainerNameDecl(root).value).toBe('test test2')
})

it('does not assign name if the array of names is empty', async () => {
const { root } = await run('', [])

expect(findContainerNameDecl(root)).toBeFalsy()
})
})
})

0 comments on commit cc7e745

Please sign in to comment.