441 lines
9.4 KiB
JavaScript
441 lines
9.4 KiB
JavaScript
|
import postcss from 'postcss'
|
||
|
import plugin from '../src/lib/substituteResponsiveAtRules'
|
||
|
import config from '../stubs/defaultConfig.stub.js'
|
||
|
|
||
|
function run(input, opts = config) {
|
||
|
return postcss([plugin(opts)]).process(input, { from: undefined })
|
||
|
}
|
||
|
|
||
|
test('it can generate responsive variants', () => {
|
||
|
const input = `
|
||
|
@responsive {
|
||
|
.banana { color: yellow; }
|
||
|
.chocolate { color: brown; }
|
||
|
}
|
||
|
|
||
|
@tailwind screens;
|
||
|
`
|
||
|
|
||
|
const output = `
|
||
|
.banana { color: yellow; }
|
||
|
.chocolate { color: brown; }
|
||
|
@media (min-width: 500px) {
|
||
|
.sm\\:banana { color: yellow; }
|
||
|
.sm\\:chocolate { color: brown; }
|
||
|
}
|
||
|
@media (min-width: 750px) {
|
||
|
.md\\:banana { color: yellow; }
|
||
|
.md\\:chocolate { color: brown; }
|
||
|
}
|
||
|
@media (min-width: 1000px) {
|
||
|
.lg\\:banana { color: yellow; }
|
||
|
.lg\\:chocolate { color: brown; }
|
||
|
}
|
||
|
`
|
||
|
|
||
|
return run(input, {
|
||
|
theme: {
|
||
|
screens: {
|
||
|
sm: '500px',
|
||
|
md: '750px',
|
||
|
lg: '1000px',
|
||
|
},
|
||
|
},
|
||
|
separator: ':',
|
||
|
}).then((result) => {
|
||
|
expect(result.css).toMatchCss(output)
|
||
|
expect(result.warnings().length).toBe(0)
|
||
|
})
|
||
|
})
|
||
|
|
||
|
test('it can generate responsive variants with a custom separator', () => {
|
||
|
const input = `
|
||
|
@responsive {
|
||
|
.banana { color: yellow; }
|
||
|
.chocolate { color: brown; }
|
||
|
}
|
||
|
|
||
|
@tailwind screens;
|
||
|
`
|
||
|
|
||
|
const output = `
|
||
|
.banana { color: yellow; }
|
||
|
.chocolate { color: brown; }
|
||
|
@media (min-width: 500px) {
|
||
|
.sm__banana { color: yellow; }
|
||
|
.sm__chocolate { color: brown; }
|
||
|
}
|
||
|
@media (min-width: 750px) {
|
||
|
.md__banana { color: yellow; }
|
||
|
.md__chocolate { color: brown; }
|
||
|
}
|
||
|
@media (min-width: 1000px) {
|
||
|
.lg__banana { color: yellow; }
|
||
|
.lg__chocolate { color: brown; }
|
||
|
}
|
||
|
`
|
||
|
|
||
|
return run(input, {
|
||
|
theme: {
|
||
|
screens: {
|
||
|
sm: '500px',
|
||
|
md: '750px',
|
||
|
lg: '1000px',
|
||
|
},
|
||
|
},
|
||
|
separator: '__',
|
||
|
}).then((result) => {
|
||
|
expect(result.css).toMatchCss(output)
|
||
|
expect(result.warnings().length).toBe(0)
|
||
|
})
|
||
|
})
|
||
|
|
||
|
test('it can generate responsive variants when classes have non-standard characters', () => {
|
||
|
const input = `
|
||
|
@responsive {
|
||
|
.hover\\:banana { color: yellow; }
|
||
|
.chocolate-2\\.5 { color: brown; }
|
||
|
.group:hover .group-hover\\:toast { color: black; }
|
||
|
}
|
||
|
|
||
|
@tailwind screens;
|
||
|
`
|
||
|
|
||
|
const output = `
|
||
|
.hover\\:banana { color: yellow; }
|
||
|
.chocolate-2\\.5 { color: brown; }
|
||
|
.group:hover .group-hover\\:toast { color: black; }
|
||
|
@media (min-width: 500px) {
|
||
|
.sm\\:hover\\:banana { color: yellow; }
|
||
|
.sm\\:chocolate-2\\.5 { color: brown; }
|
||
|
.group:hover .sm\\:group-hover\\:toast { color: black; }
|
||
|
}
|
||
|
@media (min-width: 750px) {
|
||
|
.md\\:hover\\:banana { color: yellow; }
|
||
|
.md\\:chocolate-2\\.5 { color: brown; }
|
||
|
.group:hover .md\\:group-hover\\:toast { color: black; }
|
||
|
}
|
||
|
@media (min-width: 1000px) {
|
||
|
.lg\\:hover\\:banana { color: yellow; }
|
||
|
.lg\\:chocolate-2\\.5 { color: brown; }
|
||
|
.group:hover .lg\\:group-hover\\:toast { color: black; }
|
||
|
}
|
||
|
`
|
||
|
|
||
|
return run(input, {
|
||
|
theme: {
|
||
|
screens: {
|
||
|
sm: '500px',
|
||
|
md: '750px',
|
||
|
lg: '1000px',
|
||
|
},
|
||
|
},
|
||
|
separator: ':',
|
||
|
}).then((result) => {
|
||
|
expect(result.css).toMatchCss(output)
|
||
|
expect(result.warnings().length).toBe(0)
|
||
|
})
|
||
|
})
|
||
|
|
||
|
test('responsive variants are grouped', () => {
|
||
|
const input = `
|
||
|
@responsive {
|
||
|
.banana { color: yellow; }
|
||
|
}
|
||
|
|
||
|
.apple { color: red; }
|
||
|
|
||
|
@responsive {
|
||
|
.chocolate { color: brown; }
|
||
|
}
|
||
|
|
||
|
@tailwind screens;
|
||
|
`
|
||
|
|
||
|
const output = `
|
||
|
.banana { color: yellow; }
|
||
|
.apple { color: red; }
|
||
|
.chocolate { color: brown; }
|
||
|
@media (min-width: 500px) {
|
||
|
.sm\\:banana { color: yellow; }
|
||
|
.sm\\:chocolate { color: brown; }
|
||
|
}
|
||
|
@media (min-width: 750px) {
|
||
|
.md\\:banana { color: yellow; }
|
||
|
.md\\:chocolate { color: brown; }
|
||
|
}
|
||
|
@media (min-width: 1000px) {
|
||
|
.lg\\:banana { color: yellow; }
|
||
|
.lg\\:chocolate { color: brown; }
|
||
|
}
|
||
|
`
|
||
|
|
||
|
return run(input, {
|
||
|
theme: {
|
||
|
screens: {
|
||
|
sm: '500px',
|
||
|
md: '750px',
|
||
|
lg: '1000px',
|
||
|
},
|
||
|
},
|
||
|
separator: ':',
|
||
|
}).then((result) => {
|
||
|
expect(result.css).toMatchCss(output)
|
||
|
expect(result.warnings().length).toBe(0)
|
||
|
})
|
||
|
})
|
||
|
|
||
|
test('it can generate responsive variants for nested at-rules', () => {
|
||
|
const input = `
|
||
|
@responsive {
|
||
|
.banana { color: yellow; }
|
||
|
|
||
|
@supports(display: grid) {
|
||
|
.grid\\:banana { color: blue; }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@tailwind screens;
|
||
|
`
|
||
|
|
||
|
const output = `
|
||
|
.banana {
|
||
|
color: yellow;
|
||
|
}
|
||
|
|
||
|
@supports(display: grid) {
|
||
|
.grid\\:banana {
|
||
|
color: blue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@media (min-width: 500px) {
|
||
|
.sm\\:banana {
|
||
|
color: yellow;
|
||
|
}
|
||
|
|
||
|
@supports(display: grid) {
|
||
|
.sm\\:grid\\:banana {
|
||
|
color: blue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@media (min-width: 1000px) {
|
||
|
.lg\\:banana {
|
||
|
color: yellow;
|
||
|
}
|
||
|
|
||
|
@supports(display: grid) {
|
||
|
.lg\\:grid\\:banana {
|
||
|
color: blue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
`
|
||
|
|
||
|
return run(input, {
|
||
|
theme: {
|
||
|
screens: {
|
||
|
sm: '500px',
|
||
|
lg: '1000px',
|
||
|
},
|
||
|
},
|
||
|
separator: ':',
|
||
|
}).then((result) => {
|
||
|
expect(result.css).toMatchCss(output)
|
||
|
expect(result.warnings().length).toBe(0)
|
||
|
})
|
||
|
})
|
||
|
|
||
|
test('it can generate responsive variants for deeply nested at-rules', () => {
|
||
|
const input = `
|
||
|
@responsive {
|
||
|
.banana { color: yellow; }
|
||
|
|
||
|
@supports(display: grid) {
|
||
|
@supports(display: flex) {
|
||
|
.flex-grid\\:banana { color: blue; }
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@tailwind screens;
|
||
|
`
|
||
|
|
||
|
const output = `
|
||
|
.banana {
|
||
|
color: yellow;
|
||
|
}
|
||
|
|
||
|
@supports(display: grid) {
|
||
|
@supports(display: flex) {
|
||
|
.flex-grid\\:banana {
|
||
|
color: blue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@media (min-width: 500px) {
|
||
|
.sm\\:banana {
|
||
|
color: yellow;
|
||
|
}
|
||
|
|
||
|
@supports(display: grid) {
|
||
|
@supports(display: flex) {
|
||
|
.sm\\:flex-grid\\:banana {
|
||
|
color: blue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@media (min-width: 1000px) {
|
||
|
.lg\\:banana {
|
||
|
color: yellow;
|
||
|
}
|
||
|
|
||
|
@supports(display: grid) {
|
||
|
@supports(display: flex) {
|
||
|
.lg\\:flex-grid\\:banana {
|
||
|
color: blue;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
`
|
||
|
|
||
|
return run(input, {
|
||
|
theme: {
|
||
|
screens: {
|
||
|
sm: '500px',
|
||
|
lg: '1000px',
|
||
|
},
|
||
|
},
|
||
|
separator: ':',
|
||
|
}).then((result) => {
|
||
|
expect(result.css).toMatchCss(output)
|
||
|
expect(result.warnings().length).toBe(0)
|
||
|
})
|
||
|
})
|
||
|
|
||
|
test('screen prefix is only applied to the last class in a selector', () => {
|
||
|
const input = `
|
||
|
@responsive {
|
||
|
.banana li * .sandwich #foo > div { color: yellow; }
|
||
|
}
|
||
|
|
||
|
@tailwind screens;
|
||
|
`
|
||
|
|
||
|
const output = `
|
||
|
.banana li * .sandwich #foo > div { color: yellow; }
|
||
|
@media (min-width: 500px) {
|
||
|
.banana li * .sm\\:sandwich #foo > div { color: yellow; }
|
||
|
}
|
||
|
@media (min-width: 750px) {
|
||
|
.banana li * .md\\:sandwich #foo > div { color: yellow; }
|
||
|
}
|
||
|
@media (min-width: 1000px) {
|
||
|
.banana li * .lg\\:sandwich #foo > div { color: yellow; }
|
||
|
}
|
||
|
`
|
||
|
|
||
|
return run(input, {
|
||
|
theme: {
|
||
|
screens: {
|
||
|
sm: '500px',
|
||
|
md: '750px',
|
||
|
lg: '1000px',
|
||
|
},
|
||
|
},
|
||
|
separator: ':',
|
||
|
}).then((result) => {
|
||
|
expect(result.css).toMatchCss(output)
|
||
|
expect(result.warnings().length).toBe(0)
|
||
|
})
|
||
|
})
|
||
|
|
||
|
test('responsive variants are generated for all selectors in a rule', () => {
|
||
|
const input = `
|
||
|
@responsive {
|
||
|
.foo, .bar { color: yellow; }
|
||
|
}
|
||
|
|
||
|
@tailwind screens;
|
||
|
`
|
||
|
|
||
|
const output = `
|
||
|
.foo, .bar { color: yellow; }
|
||
|
@media (min-width: 500px) {
|
||
|
.sm\\:foo, .sm\\:bar { color: yellow; }
|
||
|
}
|
||
|
@media (min-width: 750px) {
|
||
|
.md\\:foo, .md\\:bar { color: yellow; }
|
||
|
}
|
||
|
@media (min-width: 1000px) {
|
||
|
.lg\\:foo, .lg\\:bar { color: yellow; }
|
||
|
}
|
||
|
`
|
||
|
|
||
|
return run(input, {
|
||
|
theme: {
|
||
|
screens: {
|
||
|
sm: '500px',
|
||
|
md: '750px',
|
||
|
lg: '1000px',
|
||
|
},
|
||
|
},
|
||
|
separator: ':',
|
||
|
}).then((result) => {
|
||
|
expect(result.css).toMatchCss(output)
|
||
|
expect(result.warnings().length).toBe(0)
|
||
|
})
|
||
|
})
|
||
|
|
||
|
test('selectors with no classes cannot be made responsive', () => {
|
||
|
const input = `
|
||
|
@responsive {
|
||
|
div { color: yellow; }
|
||
|
}
|
||
|
|
||
|
@tailwind screens;
|
||
|
`
|
||
|
expect.assertions(1)
|
||
|
return run(input, {
|
||
|
theme: {
|
||
|
screens: {
|
||
|
sm: '500px',
|
||
|
md: '750px',
|
||
|
lg: '1000px',
|
||
|
},
|
||
|
},
|
||
|
separator: ':',
|
||
|
}).catch((e) => {
|
||
|
expect(e).toMatchObject({ name: 'CssSyntaxError' })
|
||
|
})
|
||
|
})
|
||
|
|
||
|
test('all selectors in a rule must contain classes', () => {
|
||
|
const input = `
|
||
|
@responsive {
|
||
|
.foo, div { color: yellow; }
|
||
|
}
|
||
|
|
||
|
@tailwind screens;
|
||
|
`
|
||
|
expect.assertions(1)
|
||
|
return run(input, {
|
||
|
theme: {
|
||
|
screens: {
|
||
|
sm: '500px',
|
||
|
md: '750px',
|
||
|
lg: '1000px',
|
||
|
},
|
||
|
},
|
||
|
separator: ':',
|
||
|
}).catch((e) => {
|
||
|
expect(e).toMatchObject({ name: 'CssSyntaxError' })
|
||
|
})
|
||
|
})
|