tailwindcss/tests/responsiveAtRule.test.js
Robin Malfait d497777202 [WIP] Unify JIT and AOT code paths (#4188)
* WIP

* WIP

* Finish combining JIT and AOT plugins

Still lots of clean up that can be done in some of the more complex ones, but at least it's one file per plugin now.

* Remove unused import

* Fix AOT generation bugs

* Move corePlugins/index.js to corePlugins.js

* Convert JIT files to ESM

* Move tests

* Reorder core plugins to match JIT order

* Update AOT apply tests

* Unify utils

* Combine plugin lists to one single source of truth

* Finish resolving merge conflicts, fix tests

Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
2021-05-07 13:56:15 -04:00

441 lines
9.0 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' })
})
})