1419 lines
41 KiB
JavaScript
1419 lines
41 KiB
JavaScript
let { readFileSync } = require('fs')
|
|
let { restoreAll, spyOn } = require('nanospy')
|
|
let { join } = require('path')
|
|
let postcss = require('postcss')
|
|
let { test } = require('uvu')
|
|
let { equal, match, not, ok, throws, type } = require('uvu/assert')
|
|
|
|
let autoprefixer = require('..')
|
|
|
|
let grider = autoprefixer({
|
|
cascade: false,
|
|
grid: 'autoplace',
|
|
overrideBrowserslist: ['Chrome 25', 'Edge 12', 'IE 10']
|
|
})
|
|
|
|
let cleaner = autoprefixer({
|
|
overrideBrowserslist: []
|
|
})
|
|
let compiler = autoprefixer({
|
|
overrideBrowserslist: ['Chrome 25', 'Opera 12']
|
|
})
|
|
let filterer = autoprefixer({
|
|
overrideBrowserslist: ['Chrome 25', 'Safari 9', 'Firefox 39']
|
|
})
|
|
let borderer = autoprefixer({
|
|
overrideBrowserslist: ['Safari 4', 'Firefox 3.6']
|
|
})
|
|
let cascader = autoprefixer({
|
|
cascade: true,
|
|
overrideBrowserslist: ['Chrome > 19', 'Firefox 21', 'IE 10']
|
|
})
|
|
let keyframer = autoprefixer({
|
|
overrideBrowserslist: ['Chrome > 19', 'Opera 12']
|
|
})
|
|
let flexboxer = autoprefixer({
|
|
overrideBrowserslist: ['Chrome > 19', 'Firefox 21', 'IE 10']
|
|
})
|
|
let without3d = autoprefixer({
|
|
overrideBrowserslist: ['Opera 12', 'IE > 0']
|
|
})
|
|
let supporter = autoprefixer({
|
|
overrideBrowserslist: ['Chrome 25', 'Chrome 28', 'IE > 0']
|
|
})
|
|
let uncascader = autoprefixer({
|
|
overrideBrowserslist: ['Firefox 15']
|
|
})
|
|
let gradienter = autoprefixer({
|
|
overrideBrowserslist: ['Chrome 25', 'Opera 12', 'Android 2.3']
|
|
})
|
|
let grouping = autoprefixer({
|
|
grid: 'autoplace',
|
|
overrideBrowserslist: ['Chrome 25', 'Firefox > 17', 'IE 10', 'Edge 12']
|
|
})
|
|
let ffgradienter = autoprefixer({
|
|
overrideBrowserslist: ['Chrome 25', 'Opera 12', 'Firefox 6']
|
|
})
|
|
let selectorer = autoprefixer({
|
|
overrideBrowserslist: ['Chrome 25', 'Firefox > 17', 'IE 10', 'Edge 12']
|
|
})
|
|
let fileSelectorButtoner = autoprefixer({
|
|
overrideBrowserslist: ['Chrome > 25', 'Firefox >= 82']
|
|
})
|
|
let backdroper = autoprefixer({
|
|
overrideBrowserslist: ['IE >= 11', 'Chrome < 32', 'Safari >= 15.4']
|
|
})
|
|
let placeholderShowner = autoprefixer({
|
|
overrideBrowserslist: ['IE >= 10']
|
|
})
|
|
let transitionSpec = autoprefixer({
|
|
overrideBrowserslist: ['Chrome > 19', 'Firefox 14', 'IE 10', 'Opera 12']
|
|
})
|
|
let intrinsicer = autoprefixer({
|
|
overrideBrowserslist: ['Chrome 25', 'Firefox 22', 'Safari 10']
|
|
})
|
|
let imagerender = autoprefixer({
|
|
overrideBrowserslist: ['iOS 8', 'iOS 6.1', 'FF 22', 'IE 11', 'Opera 12']
|
|
})
|
|
let backgrounder = autoprefixer({
|
|
overrideBrowserslist: ['Firefox 3.6', 'Android 2.3']
|
|
})
|
|
let resolutioner = autoprefixer({
|
|
overrideBrowserslist: ['Safari 7', 'Opera 12', 'Firefox 15']
|
|
})
|
|
let letterer = autoprefixer({
|
|
overrideBrowserslist: ['Safari 15']
|
|
})
|
|
let overscroller = autoprefixer({
|
|
overrideBrowserslist: ['Edge 17']
|
|
})
|
|
let clipper = autoprefixer({
|
|
overrideBrowserslist: ['Safari 7', 'Edge 14']
|
|
})
|
|
let example = autoprefixer({
|
|
overrideBrowserslist: ['defaults']
|
|
})
|
|
let autofiller = autoprefixer({
|
|
overrideBrowserslist: ['Chrome > 90', 'Firefox >= 82']
|
|
})
|
|
let textDecorator = autoprefixer({
|
|
overrideBrowserslist: ['Chrome >= 57', 'Firefox >= 36', 'Safari >= 12.1']
|
|
})
|
|
let content = autoprefixer({
|
|
overrideBrowserslist: [
|
|
'> 2%',
|
|
'last 2 years',
|
|
'ie 11',
|
|
'not ie_mob > 0',
|
|
'not dead'
|
|
]
|
|
})
|
|
|
|
function prefixer(name) {
|
|
if (
|
|
name === 'grid' ||
|
|
name === 'grid-gap' ||
|
|
name === 'grid-area' ||
|
|
name === 'grid-template' ||
|
|
name === 'grid-template-areas'
|
|
) {
|
|
return grider
|
|
} else if (
|
|
name === 'filter' ||
|
|
name === 'advanced-filter' ||
|
|
name === 'element'
|
|
) {
|
|
return filterer
|
|
} else if (
|
|
name === 'vendor-hack' ||
|
|
name === 'value-hack' ||
|
|
name === 'mistakes'
|
|
) {
|
|
return cleaner
|
|
} else if (
|
|
name === 'flexbox' ||
|
|
name === 'flex-rewrite' ||
|
|
name === 'double' ||
|
|
name === 'viewport' ||
|
|
name === 'appearance'
|
|
) {
|
|
return flexboxer
|
|
} else if (
|
|
name === 'intrinsic' ||
|
|
name === 'multicolumn' ||
|
|
name === 'logical' ||
|
|
name === 'text-decoration' ||
|
|
name === 'at-rules'
|
|
) {
|
|
return intrinsicer
|
|
} else if (name === 'text-decoration-shorthand') {
|
|
return textDecorator
|
|
} else if (name === 'selectors' || name === 'placeholder') {
|
|
return selectorer
|
|
} else if (name === 'selectors' || name === 'file-selector-button') {
|
|
return fileSelectorButtoner
|
|
} else if (name === 'selectors' || name === 'backdrop') {
|
|
return backdroper
|
|
} else if (
|
|
name === 'selectors' ||
|
|
name === 'autofill' ||
|
|
name === 'print-color-adjust'
|
|
) {
|
|
return autofiller
|
|
} else if (name === 'placeholder-shown') {
|
|
return placeholderShowner
|
|
} else if (name === 'backdrop-filter' || name === 'overscroll-behavior') {
|
|
return overscroller
|
|
} else if (name === 'background-clip' || name === 'user-select') {
|
|
return clipper
|
|
} else if (name === 'image-rendering' || name === 'writing-mode') {
|
|
return imagerender
|
|
} else if (name === 'keyframes') {
|
|
return keyframer
|
|
} else if (name === 'border-radius') {
|
|
return borderer
|
|
} else if (name === 'gradient') {
|
|
return gradienter
|
|
} else if (name === 'gradient-fix') {
|
|
return ffgradienter
|
|
} else if (name === 'grouping-rule') {
|
|
return grouping
|
|
} else if (name === 'cascade') {
|
|
return cascader
|
|
} else if (name === '3d-transform') {
|
|
return without3d
|
|
} else if (name === 'background-size') {
|
|
return backgrounder
|
|
} else if (name === 'uncascade') {
|
|
return uncascader
|
|
} else if (name === 'example') {
|
|
return example
|
|
} else if (name === 'resolution') {
|
|
return resolutioner
|
|
} else if (name === 'initial-letter') {
|
|
return letterer
|
|
} else if (name === 'supports') {
|
|
return supporter
|
|
} else if (name === 'transition-spec') {
|
|
return transitionSpec
|
|
} else if (name === 'content') {
|
|
return content
|
|
} else {
|
|
return compiler
|
|
}
|
|
}
|
|
|
|
function read(name) {
|
|
let file = join(__dirname, '/cases/' + name + '.css')
|
|
return readFileSync(file).toString()
|
|
}
|
|
|
|
function universalizer(string) {
|
|
return string.replace(/\r/g, '')
|
|
}
|
|
|
|
function check(from, instance = prefixer(from)) {
|
|
let input = read(from)
|
|
let output = read(from + '.out')
|
|
let result = postcss([instance]).process(input)
|
|
equal(result.warnings().length, 0)
|
|
equal(universalizer(result.css), universalizer(output))
|
|
}
|
|
|
|
const COMMONS = [
|
|
'transition',
|
|
'values',
|
|
'keyframes',
|
|
'gradient',
|
|
'flex-rewrite',
|
|
'flexbox',
|
|
'filter',
|
|
'border-image',
|
|
'border-radius',
|
|
'notes',
|
|
'selectors',
|
|
'placeholder',
|
|
'placeholder-shown',
|
|
'fullscreen',
|
|
'intrinsic',
|
|
'mistakes',
|
|
'custom-prefix',
|
|
'cascade',
|
|
'double',
|
|
'multicolumn',
|
|
'3d-transform',
|
|
'background-size',
|
|
'supports',
|
|
'viewport',
|
|
'resolution',
|
|
'logical',
|
|
'appearance',
|
|
'advanced-filter',
|
|
'element',
|
|
'image-set',
|
|
'image-rendering',
|
|
'mask-border',
|
|
'writing-mode',
|
|
'cross-fade',
|
|
'gradient-fix',
|
|
'text-emphasis-position',
|
|
'grid',
|
|
'grid-area',
|
|
'grid-template',
|
|
'grid-template-areas',
|
|
'grid-gap',
|
|
'print-color-adjust',
|
|
'initial-letter'
|
|
]
|
|
|
|
test.after.each(() => {
|
|
delete process.env.AUTOPREFIXER_GRID
|
|
restoreAll()
|
|
})
|
|
|
|
test('throws on wrong options', () => {
|
|
throws(() => {
|
|
autoprefixer({ browser: ['chrome 25', 'opera 12'] })
|
|
}, /overrideBrowserslist/)
|
|
throws(() => {
|
|
autoprefixer({
|
|
browserslist: ['chrome 25', 'opera 12']
|
|
})
|
|
}, /overrideBrowserslist/)
|
|
})
|
|
|
|
let options = {
|
|
cascade: false,
|
|
grid: false
|
|
}
|
|
|
|
let browsers = ['chrome 25', 'opera 12']
|
|
|
|
test('sets options via options object', () => {
|
|
let allOptions = Object.assign(options, { overrideBrowserslist: browsers })
|
|
let instance = autoprefixer(allOptions)
|
|
equal(instance.options, allOptions)
|
|
equal(instance.browsers, browsers)
|
|
})
|
|
|
|
test('sets options via array of browsers as first argument and object', () => {
|
|
let instance = autoprefixer(browsers, options)
|
|
equal(instance.options, options)
|
|
equal(instance.browsers, browsers)
|
|
})
|
|
|
|
test('sets options via browsers as arguments and options object', () => {
|
|
let instance = autoprefixer(...browsers, options)
|
|
equal(instance.options, options)
|
|
equal(instance.browsers, browsers)
|
|
})
|
|
|
|
test('has default browsers', () => {
|
|
type(autoprefixer.defaults.length, 'number')
|
|
})
|
|
|
|
test('shows warning on browsers option', () => {
|
|
let consoleWarn = spyOn(console, 'warn', () => {})
|
|
let instance = autoprefixer({
|
|
browsers: ['last 1 version']
|
|
})
|
|
equal(instance.browsers, ['last 1 version'])
|
|
equal(consoleWarn.callCount, 1)
|
|
match(consoleWarn.calls[0][0], 'overrideBrowserslist')
|
|
})
|
|
|
|
test('passes statistics to Browserslist', () => {
|
|
let stats = {
|
|
chrome: {
|
|
10: 10,
|
|
11: 40
|
|
},
|
|
ie: {
|
|
10: 10,
|
|
11: 40
|
|
}
|
|
}
|
|
match(
|
|
autoprefixer({
|
|
overrideBrowserslist: '> 20% in my stats',
|
|
stats
|
|
}).info(),
|
|
/Browsers:\n\s\sChrome: 11\n\s\sIE: 11\n/
|
|
)
|
|
})
|
|
|
|
test('prefixes values', () => {
|
|
check('values')
|
|
})
|
|
|
|
test('prefixes @keyframes', () => {
|
|
check('keyframes')
|
|
})
|
|
|
|
test('prefixes @viewport', () => {
|
|
check('viewport')
|
|
})
|
|
|
|
test('prefixes selectors', () => {
|
|
check('selectors')
|
|
})
|
|
|
|
test('prefixes uppercase pseudo-elements', () => {
|
|
let css = 'input::PLACEHOLDER { color: red }'
|
|
let plugin = autoprefixer({ overrideBrowserslist: ['Chrome 40'] })
|
|
equal(
|
|
postcss([plugin]).process(css, { from: undefined }).css,
|
|
'input::-webkit-input-placeholder { color: red }\n' + css
|
|
)
|
|
})
|
|
|
|
test('prefixes mixed-case pseudo-classes without changing selector case', () => {
|
|
let css = '.Field#Input[type="TEXT"]:Read-Only { color: red }'
|
|
let plugin = autoprefixer({ overrideBrowserslist: ['Firefox 39'] })
|
|
equal(
|
|
postcss([plugin]).process(css, { from: undefined }).css,
|
|
'.Field#Input[type="TEXT"]:-moz-read-only { color: red }\n' + css
|
|
)
|
|
})
|
|
|
|
test('prefixes every matching selector regardless of case', () => {
|
|
let css = 'input::placeholder, textarea::PlaceHolder { color: red }'
|
|
let plugin = autoprefixer({ overrideBrowserslist: ['Chrome 40'] })
|
|
equal(
|
|
postcss([plugin]).process(css, { from: undefined }).css,
|
|
'input::-webkit-input-placeholder, ' +
|
|
'textarea::-webkit-input-placeholder { color: red }\n' +
|
|
css
|
|
)
|
|
})
|
|
|
|
test('prefixes resolution query', () => {
|
|
check('resolution')
|
|
})
|
|
|
|
test('does not hang on long resolution query', () => {
|
|
let css = `@media (min-resolution: ${'9'.repeat(128000)}z) { a { color: red } }`
|
|
let start = Date.now()
|
|
let out = postcss([resolutioner]).process(css, { from: undefined }).css
|
|
equal(out, css)
|
|
ok(Date.now() - start < 2000)
|
|
})
|
|
|
|
test('removes common mistakes', () => {
|
|
check('mistakes')
|
|
})
|
|
|
|
test('reads notes for prefixes', () => {
|
|
check('notes')
|
|
})
|
|
|
|
test('keeps vendor-specific hacks', () => {
|
|
check('vendor-hack')
|
|
})
|
|
|
|
test('keeps values with vendor hacks', () => {
|
|
check('value-hack')
|
|
})
|
|
|
|
test('works with comments', () => {
|
|
check('comments')
|
|
})
|
|
|
|
test('uses visual cascade', () => {
|
|
check('cascade')
|
|
})
|
|
|
|
test('works with properties near', () => {
|
|
check('double')
|
|
})
|
|
|
|
test('checks prefixed in hacks', () => {
|
|
check('check-down')
|
|
})
|
|
|
|
test('normalize cascade after remove', () => {
|
|
check('uncascade')
|
|
})
|
|
|
|
test('prefix decls in @supports', () => {
|
|
check('supports')
|
|
})
|
|
|
|
test('saves declaration style', () => {
|
|
check('style')
|
|
})
|
|
|
|
test('uses ignore next control comments', () => {
|
|
check('ignore-next')
|
|
})
|
|
|
|
test('uses block control comments', () => {
|
|
check('disabled')
|
|
})
|
|
|
|
test('has actual example in docs', () => {
|
|
check('example')
|
|
})
|
|
|
|
test('process grouping rules correctly', () => {
|
|
check('grouping-rule')
|
|
})
|
|
|
|
test('transition on vendor specific rule', () => {
|
|
check('transition-spec')
|
|
})
|
|
|
|
test('ignore prefix in vendor at rules', () => {
|
|
check('at-rules')
|
|
})
|
|
|
|
test('ignore content property', () => {
|
|
let input = read('content')
|
|
let result = postcss([prefixer('scope')]).process(input)
|
|
equal(result.css, input)
|
|
})
|
|
|
|
test('uses control comments to whole scope', () => {
|
|
let input = read('scope')
|
|
let output = read('scope.out')
|
|
let result = postcss([prefixer('scope')]).process(input)
|
|
|
|
equal(result.css, output)
|
|
equal(
|
|
result.warnings().map(i => i.toString()),
|
|
[
|
|
'autoprefixer: <css input>:5:3: Second Autoprefixer control comment ' +
|
|
'was ignored. Autoprefixer applies control comment to whole block, ' +
|
|
'not to next rules.'
|
|
]
|
|
)
|
|
})
|
|
|
|
test('sets grid option via comment', () => {
|
|
let input = read('grid-status')
|
|
let output = read('grid-status.out')
|
|
let ap = autoprefixer({ overrideBrowserslist: ['last 2 versions', 'IE 11'] })
|
|
let result = postcss([ap]).process(input)
|
|
|
|
equal(result.css, output)
|
|
equal(
|
|
result.warnings().map(i => i.toString()),
|
|
[
|
|
'autoprefixer: <css input>:2:1: Second Autoprefixer grid control ' +
|
|
'comment was ignored. Autoprefixer applies control comments ' +
|
|
'to the whole block, not to the next rules.',
|
|
'autoprefixer: <css input>:20:3: Second Autoprefixer grid control ' +
|
|
'comment was ignored. Autoprefixer applies control comments ' +
|
|
'to the whole block, not to the next rules.',
|
|
'autoprefixer: <css input>:47:3: Second Autoprefixer grid control ' +
|
|
'comment was ignored. Autoprefixer applies control comments ' +
|
|
'to the whole block, not to the next rules.'
|
|
]
|
|
)
|
|
})
|
|
|
|
test('prefixes transition', () => {
|
|
let input = read('transition')
|
|
let output = read('transition.out')
|
|
let result = postcss([prefixer('transition')]).process(input)
|
|
|
|
equal(result.css, output)
|
|
equal(
|
|
result.warnings().map(i => i.toString()),
|
|
[
|
|
'autoprefixer: <css input>:23:3: Replace transition-property ' +
|
|
'to transition, because Autoprefixer could not support any cases ' +
|
|
'of transition-property and other transition-*'
|
|
]
|
|
)
|
|
})
|
|
|
|
test('does not raise unnecessary warnings when prefixing transition', () => {
|
|
check('transition-no-warning')
|
|
})
|
|
|
|
test('works with broken transition', () => {
|
|
let input = 'a{transition:,,}'
|
|
let output = 'a{-webkit-transition:;-o-transition:;transition:}'
|
|
let result = postcss([prefixer('transition')]).process(input)
|
|
equal(result.css, output)
|
|
})
|
|
|
|
test('should ignore spaces inside values', () => {
|
|
let css = read('trim')
|
|
equal(postcss([flexboxer]).process(css).css, css)
|
|
})
|
|
|
|
test('removes unnecessary prefixes', () => {
|
|
let processor = postcss([cleaner])
|
|
for (let i of COMMONS) {
|
|
if (i === 'gradient-fix') continue
|
|
if (i === 'cascade') continue
|
|
if (i === 'mistakes') continue
|
|
if (i === 'flex-rewrite') continue
|
|
if (i === 'grid') continue
|
|
if (i === 'grid-gap') continue
|
|
if (i === 'grid-area') continue
|
|
if (i === 'grid-template') continue
|
|
if (i === 'grid-template-areas') continue
|
|
let input = read(i + '.out')
|
|
let output = read(i)
|
|
equal(processor.process(input).css, output)
|
|
}
|
|
})
|
|
|
|
test('media does not should nested', () => {
|
|
let processor = postcss([grider])
|
|
let input = read('grid-media-rules')
|
|
let output = read('grid-media-rules.out')
|
|
equal(processor.process(input).css, output)
|
|
})
|
|
|
|
test('does not remove unnecessary prefixes on request', () => {
|
|
for (let i of ['transition', 'values', 'fullscreen']) {
|
|
let keeper = autoprefixer({ overrideBrowserslist: [], remove: false })
|
|
let css = read(i + '.out')
|
|
equal(postcss([keeper]).process(css).css, css)
|
|
}
|
|
})
|
|
|
|
test('does not add prefixes on request', () => {
|
|
for (let i of ['transition', 'values', 'fullscreen']) {
|
|
let remover = autoprefixer({
|
|
add: false,
|
|
overrideBrowserslist: ['Opera 12']
|
|
})
|
|
let unprefixed = read(i)
|
|
equal(postcss([remover]).process(unprefixed).css, unprefixed)
|
|
}
|
|
})
|
|
|
|
test('prevents doubling prefixes', () => {
|
|
for (let i of COMMONS) {
|
|
let processor = postcss([prefixer(i)])
|
|
let input = read(i)
|
|
let output = read(i + '.out')
|
|
let result = processor.process(processor.process(input)).css
|
|
equal(universalizer(result), universalizer(output))
|
|
}
|
|
})
|
|
|
|
function isContainerNode(node) {
|
|
return 'nodes' in node
|
|
}
|
|
|
|
test('does not broke AST', () => {
|
|
function checkParent(node) {
|
|
node.walk(child => {
|
|
type(child.parent, 'object')
|
|
if (isContainerNode(child)) checkParent(child)
|
|
})
|
|
}
|
|
for (let i of COMMONS) {
|
|
let processor = postcss([prefixer(i)])
|
|
let input = read(i)
|
|
checkParent(processor.process(input).root)
|
|
}
|
|
})
|
|
|
|
test('parses difficult files', () => {
|
|
let input = read('syntax')
|
|
let result = postcss([cleaner]).process(input)
|
|
equal(result.css, input)
|
|
})
|
|
|
|
test('marks parsing errors', () => {
|
|
throws(() => {
|
|
postcss([cleaner]).process('a {').css
|
|
}, '<css input>:1:1: Unclosed block')
|
|
})
|
|
|
|
test('shows file name in parse error', () => {
|
|
throws(() => {
|
|
postcss([cleaner]).process('a {', { from: 'a.css' }).css
|
|
}, /a.css:1:1: /)
|
|
})
|
|
|
|
test('uses browserslist config', () => {
|
|
let from = join(__dirname, 'cases/config/test.css')
|
|
let input = read('config/test')
|
|
let output = read('config/test.out')
|
|
let processor = postcss([autoprefixer])
|
|
equal(processor.process(input, { from }).css, output)
|
|
})
|
|
|
|
test('sets browserslist environment', () => {
|
|
let from = join(__dirname, 'cases/config/test.css')
|
|
let input = read('config/test')
|
|
let output = read('config/test.production')
|
|
let processor = postcss([autoprefixer({ env: 'development' })])
|
|
equal(processor.process(input, { from }).css, output)
|
|
})
|
|
|
|
test('takes values from other PostCSS plugins', () => {
|
|
function plugin(root) {
|
|
root.walkDecls(i => {
|
|
i.value = 'calc(0)'
|
|
})
|
|
}
|
|
let result = postcss([plugin, compiler]).process('a{width:0/**/0}')
|
|
equal(result.css, 'a{width:-webkit-calc(0);width:calc(0)}')
|
|
})
|
|
|
|
test('has option to disable @supports support', () => {
|
|
let css = '@supports (cursor: grab) {}'
|
|
let instance = autoprefixer({
|
|
overrideBrowserslist: ['Chrome 28'],
|
|
supports: false
|
|
})
|
|
let result = postcss([instance]).process(css)
|
|
equal(result.css, css)
|
|
})
|
|
|
|
test('has disabled grid options by default', () => {
|
|
let ap = autoprefixer({ overrideBrowserslist: ['Edge 12', 'IE 10'] })
|
|
let input = read('grid')
|
|
let output = read('grid.disabled')
|
|
let result = postcss([ap]).process(input)
|
|
equal(result.css, output)
|
|
})
|
|
|
|
test('has different outputs for different grid options', () => {
|
|
function ap(gridValue) {
|
|
return autoprefixer({
|
|
grid: gridValue,
|
|
overrideBrowserslist: ['Edge 12', 'IE 10']
|
|
})
|
|
}
|
|
let input = read('grid-options')
|
|
let outputAutoplace = read('grid-options.autoplace.out')
|
|
let outputNoAutoplace = read('grid-options.no-autoplace.out')
|
|
let outputDisabled = read('grid-options.disabled.out')
|
|
|
|
let resultAutoplace = postcss([ap('autoplace')]).process(input).css
|
|
let resultNoAutoplace = postcss([ap('no-autoplace')]).process(input).css
|
|
let resultEnabled = postcss([ap(true)]).process(input).css
|
|
let resultDisabled = postcss([ap(false)]).process(input).css
|
|
|
|
// output for grid: 'autoplace'
|
|
equal(resultAutoplace, outputAutoplace)
|
|
// output for grid: 'no-autoplace'
|
|
equal(resultNoAutoplace, outputNoAutoplace)
|
|
// output for grid: true is the same as for 'no-autoplace'
|
|
equal(resultEnabled, outputNoAutoplace)
|
|
// output for grid: false
|
|
equal(resultDisabled, outputDisabled)
|
|
})
|
|
|
|
test('has different outputs for different grid environment variables', () => {
|
|
function ap(gridValue) {
|
|
process.env.AUTOPREFIXER_GRID = gridValue
|
|
return autoprefixer({ overrideBrowserslist: ['Edge 12', 'IE 10'] })
|
|
}
|
|
let input = read('grid-options')
|
|
let outputAutoplace = read('grid-options.autoplace.out')
|
|
let outputNoAutoplace = read('grid-options.no-autoplace.out')
|
|
|
|
let resultAutoplace = postcss([ap('autoplace')]).process(input).css
|
|
equal(resultAutoplace, outputAutoplace)
|
|
|
|
let resultNoAutoplace = postcss([ap('no-autoplace')]).process(input).css
|
|
equal(resultNoAutoplace, outputNoAutoplace)
|
|
})
|
|
|
|
test('has option to disable flexbox support', () => {
|
|
let css = read('flexbox')
|
|
let instance = autoprefixer({
|
|
flexbox: false,
|
|
overrideBrowserslist: ['IE 10']
|
|
})
|
|
let result = postcss([instance]).process(css)
|
|
equal(result.css, css)
|
|
})
|
|
|
|
test('has option to disable 2009 flexbox support', () => {
|
|
let ap = autoprefixer({
|
|
flexbox: 'no-2009',
|
|
overrideBrowserslist: ['Chrome > 19']
|
|
})
|
|
let css = 'a{flex:1;transition:flex}'
|
|
let result = postcss([ap]).process(css)
|
|
equal(
|
|
result.css,
|
|
'a{' +
|
|
'-webkit-flex:1;flex:1;' +
|
|
'-webkit-transition:-webkit-flex;transition:-webkit-flex;' +
|
|
'transition:flex;transition:flex, -webkit-flex' +
|
|
'}'
|
|
)
|
|
})
|
|
|
|
test('returns inspect string', () => {
|
|
match(
|
|
autoprefixer({ overrideBrowserslist: ['chrome 25'] }).info(),
|
|
/Browsers:\s+Chrome: 25/
|
|
)
|
|
})
|
|
|
|
test('uses browserslist config in inspect', () => {
|
|
let from = join(__dirname, 'cases/config')
|
|
match(autoprefixer().info({ from }), /Browsers:\s+IE: 10/)
|
|
})
|
|
|
|
test('ignores unknown versions on request', () => {
|
|
throws(() => {
|
|
autoprefixer({ overrideBrowserslist: ['ie 100'] }).info()
|
|
}, /Unknown version 100 of ie/)
|
|
not.throws(() => {
|
|
autoprefixer({
|
|
ignoreUnknownVersions: true,
|
|
overrideBrowserslist: ['ie 100']
|
|
}).info()
|
|
})
|
|
})
|
|
|
|
test('works with CSS Modules', () => {
|
|
postcss([autoprefixer()]).process(':export { selectors: _1q6ho_2 }').css
|
|
})
|
|
|
|
test('ignores prefix IE filter', () => {
|
|
check('filter')
|
|
})
|
|
|
|
test('supports webkit filters', () => {
|
|
check('advanced-filter')
|
|
})
|
|
|
|
test('changes border image syntax', () => {
|
|
check('border-image')
|
|
})
|
|
|
|
test('supports old Mozilla prefixes', () => {
|
|
check('border-radius')
|
|
})
|
|
|
|
test('supports all flexbox syntaxes', () => {
|
|
check('flexbox')
|
|
})
|
|
|
|
test('supports map flexbox props', () => {
|
|
check('flex-rewrite')
|
|
})
|
|
|
|
test('supports all fullscreens', () => {
|
|
check('fullscreen')
|
|
})
|
|
|
|
test('supports file-selector-button', () => {
|
|
check('file-selector-button')
|
|
})
|
|
|
|
test('supports ::backdrop', () => {
|
|
check('backdrop')
|
|
})
|
|
|
|
test('supports custom prefixes', () => {
|
|
check('custom-prefix')
|
|
})
|
|
|
|
test('fixes break properties', () => {
|
|
check('multicolumn')
|
|
})
|
|
|
|
test('ignores some 3D transforms', () => {
|
|
check('3d-transform')
|
|
})
|
|
|
|
test('supports background-size', () => {
|
|
check('background-size')
|
|
})
|
|
|
|
test('supports background-clip', () => {
|
|
check('background-clip')
|
|
})
|
|
|
|
test('supports logical properties', () => {
|
|
check('logical')
|
|
})
|
|
|
|
test('supports appearance', () => {
|
|
check('appearance')
|
|
})
|
|
|
|
test('supports all placeholders', () => {
|
|
check('placeholder')
|
|
})
|
|
|
|
test('supports placeholder-shown', () => {
|
|
check('placeholder-shown')
|
|
})
|
|
|
|
test('supports image-rendering', () => {
|
|
check('image-rendering')
|
|
})
|
|
|
|
test('supports border-box mask', () => {
|
|
check('mask-border')
|
|
})
|
|
|
|
test('supports mask-composite', () => {
|
|
check('mask-composite')
|
|
})
|
|
|
|
test('supports mask-position-x and mask-position-y', () => {
|
|
check('mask-position')
|
|
})
|
|
|
|
test('supports image-set()', () => {
|
|
check('image-set')
|
|
})
|
|
|
|
test('supports writing-mode', () => {
|
|
check('writing-mode')
|
|
})
|
|
|
|
test('supports cross-fade()', () => {
|
|
check('cross-fade')
|
|
})
|
|
|
|
test('ignores modern direction', () => {
|
|
check('animation')
|
|
})
|
|
|
|
test('supports overscroll-behavior', () => {
|
|
check('overscroll-behavior')
|
|
})
|
|
|
|
test('supports print-color-adjust', () => {
|
|
let input = read('print-color-adjust')
|
|
let output = read('print-color-adjust.out')
|
|
let result = postcss([prefixer('print-color-adjust')]).process(input)
|
|
|
|
equal(result.css, output)
|
|
equal(
|
|
result.warnings().map(i => i.toString()),
|
|
[
|
|
'autoprefixer: <css input>:2:3: Replace color-adjust ' +
|
|
'to print-color-adjust. The color-adjust shorthand ' +
|
|
'is currently deprecated.'
|
|
]
|
|
)
|
|
})
|
|
|
|
test('supports backdrop-filter', () => {
|
|
check('backdrop-filter')
|
|
})
|
|
|
|
test('supports initial-letter', () => {
|
|
check('initial-letter')
|
|
})
|
|
|
|
test('supports user-select hack for IE', () => {
|
|
check('user-select')
|
|
})
|
|
|
|
test('supports appearance for IE', () => {
|
|
let instance = autoprefixer({ overrideBrowserslist: 'Edge 15' })
|
|
let result = postcss([instance]).process('a { appearance: none }')
|
|
equal(result.css, 'a { -webkit-appearance: none; appearance: none }')
|
|
})
|
|
|
|
test('changes angle in gradient', () => {
|
|
let input = read('gradient')
|
|
let output = read('gradient.out')
|
|
let result = postcss([prefixer('gradient')]).process(input)
|
|
|
|
equal(result.css, output)
|
|
equal(
|
|
result.warnings().map(i => i.toString()),
|
|
[
|
|
'autoprefixer: <css input>:18:3: Gradient has outdated direction ' +
|
|
'syntax. New syntax is like `closest-side at 0 0` instead of ' +
|
|
'`0 0, closest-side`.',
|
|
'autoprefixer: <css input>:38:3: Gradient has outdated direction ' +
|
|
'syntax. New syntax is like `to left` instead of `right`.',
|
|
'autoprefixer: <css input>:100:3: Gradient has outdated ' +
|
|
'direction syntax. Replace `cover` to `farthest-corner`.',
|
|
'autoprefixer: <css input>:104:3: Gradient has outdated ' +
|
|
'direction syntax. Replace `contain` to `closest-side`.'
|
|
]
|
|
)
|
|
|
|
check('gradient-fix')
|
|
})
|
|
|
|
test('skips old webkit gradient for CSS variables', () => {
|
|
let input = 'a { background: linear-gradient(var(--direction), red, blue); }'
|
|
let result = postcss([gradienter]).process(input)
|
|
|
|
// Should not generate -webkit-gradient() when CSS variables are present
|
|
equal(result.css.includes('-webkit-gradient('), false)
|
|
// Should still generate -webkit-linear-gradient()
|
|
equal(result.css.includes('-webkit-linear-gradient('), true)
|
|
})
|
|
|
|
test('skips old webkit gradients with color hints', () => {
|
|
let values = [
|
|
'linear-gradient(red 10%, 30%, blue 90%)',
|
|
'linear-gradient(to top, red 10%, 30%, blue 90%)',
|
|
'linear-gradient(red, 0, blue)',
|
|
'linear-gradient(red, 2em, blue)',
|
|
'linear-gradient(red, calc(20% + 10%), blue)',
|
|
'linear-gradient(red, min(20%, 30%), blue)',
|
|
'linear-gradient(red, max(20%, 30%), blue)',
|
|
'linear-gradient(red, clamp(20%, 30%, 40%), blue)',
|
|
'linear-gradient(red, /* hint */ 30% /* end */, blue)'
|
|
]
|
|
for (let value of values) {
|
|
let input = `a { background: ${value}; }`
|
|
let result = postcss([gradienter]).process(input)
|
|
|
|
equal(result.css.includes('-webkit-gradient('), false)
|
|
equal(result.css.includes('-webkit-linear-gradient('), true)
|
|
equal(result.css.includes(value), true)
|
|
}
|
|
})
|
|
|
|
test('keeps old webkit gradients with ordinary color stops', () => {
|
|
let input = 'a { background: linear-gradient(to top, rgba(0,0,0,0.5) 10%, ' +
|
|
'hsl(0,50%,50%) 30%, blue 90%); }'
|
|
let result = postcss([gradienter]).process(input)
|
|
|
|
equal(
|
|
result.root.first.first.value,
|
|
'-webkit-gradient(linear, left bottom, left top, ' +
|
|
'color-stop(10%, rgba(0,0,0,0.5)), ' +
|
|
'color-stop(30%, hsl(0,50%,50%)), color-stop(90%, blue))'
|
|
)
|
|
})
|
|
|
|
test('skips old webkit gradients when a background layer has a color hint', () => {
|
|
let values = [
|
|
'linear-gradient(red, blue), linear-gradient(red, 30%, blue)',
|
|
'linear-gradient(red, 30%, blue), linear-gradient(red, blue)'
|
|
]
|
|
for (let value of values) {
|
|
let input = `a { background: ${value}; }`
|
|
let result = postcss([gradienter]).process(input)
|
|
|
|
equal(result.css.includes('-webkit-gradient('), false)
|
|
equal(result.css.includes(value), true)
|
|
equal(result.css.includes('-webkit-linear-gradient('), true)
|
|
}
|
|
})
|
|
|
|
test('warns about color hints in old webkit gradients', () => {
|
|
let values = [
|
|
'linear-gradient(red 10%, 30%, blue 90%)',
|
|
'linear-gradient(red, calc(20% + 10%), blue)',
|
|
'linear-gradient(red, blue), linear-gradient(red, 30%, blue)'
|
|
]
|
|
for (let value of values) {
|
|
let input = `a { background: ${value} }`
|
|
let result = postcss([gradienter]).process(input)
|
|
|
|
equal(
|
|
result.warnings().map(i => i.toString()),
|
|
[
|
|
'autoprefixer: <css input>:1:5: Gradient color hints are not ' +
|
|
'supported by old WebKit'
|
|
]
|
|
)
|
|
}
|
|
})
|
|
|
|
test('does not warn about gradients without color hints', () => {
|
|
let values = [
|
|
'linear-gradient(red, blue)',
|
|
'linear-gradient(to top, red 10%, blue 90%)',
|
|
'linear-gradient(red, var(--middle), blue)'
|
|
]
|
|
for (let value of values) {
|
|
let input = `a { background: ${value} }`
|
|
let result = postcss([gradienter]).process(input)
|
|
|
|
equal(result.warnings().length, 0)
|
|
}
|
|
})
|
|
|
|
test('does not warn about color hints without old webkit', () => {
|
|
let instance = autoprefixer({ overrideBrowserslist: ['Chrome 25'] })
|
|
let input = 'a { background: linear-gradient(red, 30%, blue) }'
|
|
let result = postcss([instance]).process(input)
|
|
|
|
equal(result.css.includes('-webkit-linear-gradient('), true)
|
|
equal(result.warnings().length, 0)
|
|
})
|
|
|
|
test('does not throw on empty or malformed gradient arguments', () => {
|
|
let inputs = [
|
|
'a { background-image: linear-gradient() }',
|
|
'a { background-image: radial-gradient() }',
|
|
'a { background-image: repeating-linear-gradient() }',
|
|
'a { background-image: repeating-radial-gradient() }',
|
|
'a { background-image: linear-gradient(red,) }',
|
|
'a { background-image: linear-gradient(,red) }',
|
|
'a { background-image: linear-gradient(red,,blue) }',
|
|
'a { background-image: linear-gradient(to right, red,) }'
|
|
]
|
|
for (let input of inputs) {
|
|
// Would throw an uncaught TypeError before the empty-argument guards
|
|
let result = postcss([gradienter]).process(input, { from: undefined })
|
|
type(result.css, 'string')
|
|
}
|
|
})
|
|
|
|
test('warns on old flexbox display', () => {
|
|
let result = postcss([flexboxer]).process('a{ display: box; }')
|
|
equal(result.css, 'a{ display: box; }')
|
|
equal(
|
|
result.warnings().map(i => i.toString()),
|
|
[
|
|
'autoprefixer: <css input>:1:4: You should write display: flex ' +
|
|
'by final spec instead of display: box'
|
|
]
|
|
)
|
|
})
|
|
|
|
test('supports intrinsic sizing', () => {
|
|
let input = read('intrinsic')
|
|
let output = read('intrinsic.out')
|
|
let result = postcss([prefixer('intrinsic')]).process(input)
|
|
|
|
equal(result.css, output)
|
|
equal(
|
|
result.warnings().map(i => i.toString()),
|
|
[
|
|
'autoprefixer: <css input>:15:3: Replace fill to stretch, ' +
|
|
'because spec had been changed',
|
|
'autoprefixer: <css input>:19:3: Replace fill-available ' +
|
|
'to stretch, because spec had been changed'
|
|
]
|
|
)
|
|
})
|
|
|
|
test('supports text-emphasis', () => {
|
|
let input = read('text-emphasis-position')
|
|
let output = read('text-emphasis-position.out')
|
|
let instance = prefixer('text-emphasis-position')
|
|
let result = postcss([instance]).process(input)
|
|
|
|
equal(result.css, output)
|
|
equal(
|
|
result.warnings().map(i => i.toString()),
|
|
[
|
|
'autoprefixer: <css input>:14:3: You should use 2 values ' +
|
|
'for text-emphasis-position For example, `under left` ' +
|
|
'instead of just `under`.'
|
|
]
|
|
)
|
|
})
|
|
|
|
test('supports grid layout', () => {
|
|
let input = read('grid')
|
|
let output = read('grid.out')
|
|
let instance = prefixer('grid')
|
|
let result = postcss([instance]).process(input)
|
|
|
|
equal(result.css, output)
|
|
equal(
|
|
result.warnings().map(i => i.toString()),
|
|
[
|
|
'autoprefixer: <css input>:3:3: Autoplacement does not work ' +
|
|
'without grid-template-rows property',
|
|
'autoprefixer: <css input>:12:3: Autoplacement does not work ' +
|
|
'without grid-template-columns property',
|
|
'autoprefixer: <css input>:36:3: Can not prefix grid-column-end ' +
|
|
'(grid-column-start is not found)',
|
|
'autoprefixer: <css input>:37:3: IE does not support subgrid',
|
|
'autoprefixer: <css input>:39:3: Can not implement grid-gap ' +
|
|
'without grid-template-columns',
|
|
'autoprefixer: <css input>:39:3: Can not find grid areas: ' +
|
|
'head, nav, main, foot',
|
|
'autoprefixer: <css input>:57:3: Can not implement grid-gap ' +
|
|
'without grid-template-columns',
|
|
'autoprefixer: <css input>:57:3: Can not find grid areas: a',
|
|
'autoprefixer: <css input>:65:3: Can not implement grid-gap ' +
|
|
'without grid-template-columns',
|
|
'autoprefixer: <css input>:65:3: Can not find grid areas: b',
|
|
'autoprefixer: <css input>:73:3: Can not find grid areas: c',
|
|
'autoprefixer: <css input>:81:3: Can not find grid areas: d',
|
|
'autoprefixer: <css input>:116:3: grid-column-span is not part ' +
|
|
'of final Grid Layout. Use grid-column.',
|
|
'autoprefixer: <css input>:117:3: grid-row-span is not part ' +
|
|
'of final Grid Layout. Use grid-row.',
|
|
'autoprefixer: <css input>:118:3: grid-auto-columns is not ' +
|
|
'supported by IE',
|
|
'autoprefixer: <css input>:119:3: grid-auto-rows is not ' +
|
|
'supported by IE',
|
|
'autoprefixer: <css input>:121:33: auto-fill value is not ' +
|
|
'supported by IE',
|
|
'autoprefixer: <css input>:122:30: auto-fit value is not ' +
|
|
'supported by IE',
|
|
'autoprefixer: <css input>:138:3: Please do not use ' +
|
|
'display: contents; if you have grid setting enabled',
|
|
'autoprefixer: <css input>:142:3: IE does not support align-items ' +
|
|
'on grid containers. Try using align-self on child elements instead: ' +
|
|
'.warn_ie_align > * { align-self: center }',
|
|
'autoprefixer: <css input>:147:3: IE does not support justify-items ' +
|
|
'on grid containers. Try using justify-self on child elements ' +
|
|
'instead: .warn_ie_justify > * { justify-self: center }',
|
|
'autoprefixer: <css input>:152:3: IE does not support justify-content ' +
|
|
'on grid containers',
|
|
'autoprefixer: <css input>:157:3: IE does not support place-items ' +
|
|
'on grid containers. Try using place-self on child elements ' +
|
|
'instead: .warn_place_items > * { place-self: start end }',
|
|
'autoprefixer: <css input>:181:3: grid-auto-flow is not supported by IE',
|
|
'autoprefixer: <css input>:203:26: Autoprefixer currently does not ' +
|
|
'support line names. Try using grid-template-areas instead.'
|
|
]
|
|
)
|
|
|
|
let input2 = read('grid-template')
|
|
let output2 = read('grid-template.out')
|
|
let instance2 = prefixer('grid-template')
|
|
let result2 = postcss([instance2]).process(input2)
|
|
equal(result2.css, output2)
|
|
})
|
|
|
|
test('supports grid autoplacement', () => {
|
|
let input = read('grid-autoplacement')
|
|
let output = read('grid-autoplacement.out')
|
|
let instance = prefixer('grid')
|
|
let result = postcss([instance]).process(input)
|
|
equal(result.css, output)
|
|
|
|
equal(
|
|
result.warnings().map(i => i.toString()),
|
|
[
|
|
'autoprefixer: <css input>:47:3: grid-auto-flow: dense ' +
|
|
'is not supported by IE',
|
|
'autoprefixer: <css input>:48:3: Autoplacement does not work ' +
|
|
'without grid-template-rows property',
|
|
'autoprefixer: <css input>:53:3: grid-auto-flow works only if grid-temp' +
|
|
'late-rows and grid-template-columns are present in the same rule',
|
|
'autoprefixer: <css input>:60:3: grid-gap only works if grid-temp' +
|
|
'late(-areas) is being used',
|
|
'autoprefixer: <css input>:64:3: Autoplacement does not work ' +
|
|
'without grid-template-rows property',
|
|
'autoprefixer: <css input>:65:3: grid-gap only works if grid-temp' +
|
|
'late(-areas) is being used or both rows and columns have been ' +
|
|
'declared and cells have not been ' +
|
|
'manually placed inside the explicit grid'
|
|
]
|
|
)
|
|
})
|
|
|
|
test('shows Grid warnings only for IE', () => {
|
|
let input = 'a { grid-template-rows: repeat(auto-fit, 1px) }'
|
|
let instance = autoprefixer({
|
|
grid: true,
|
|
overrideBrowserslist: 'chrome 27'
|
|
})
|
|
let result = postcss([instance]).process(input)
|
|
equal(result.warnings().length, 0)
|
|
})
|
|
|
|
test('warns if rule has both grid-area and grid-(row|column) decls', () => {
|
|
let input = read('grid-area')
|
|
let instance = prefixer('grid-area')
|
|
let result = postcss([instance]).process(input)
|
|
equal(
|
|
result.warnings().map(i => i.toString()),
|
|
[
|
|
'autoprefixer: <css input>:28:3: You already have a grid-area ' +
|
|
'declaration present in the rule. You should use either ' +
|
|
'grid-area or grid-row, not both',
|
|
'autoprefixer: <css input>:29:3: You already have a grid-area ' +
|
|
'declaration present in the rule. You should use either ' +
|
|
'grid-area or grid-column, not both',
|
|
'autoprefixer: <css input>:34:3: You already have a grid-area ' +
|
|
'declaration present in the rule. You should use either ' +
|
|
'grid-area or grid-column, not both'
|
|
]
|
|
)
|
|
})
|
|
|
|
test('warns if rule with grid-area has no parent with grid-template', () => {
|
|
let input = read('grid-template-areas')
|
|
let instance = prefixer('grid-area')
|
|
let result = postcss([instance]).process(input)
|
|
|
|
equal(
|
|
result
|
|
.warnings()
|
|
.map(i => i.toString())
|
|
.filter(str => str.includes('grid-template')),
|
|
[
|
|
'autoprefixer: <css input>:144:3: Autoprefixer cannot find ' +
|
|
'a grid-template containing the duplicate grid-area ' +
|
|
'"child" with full selector matching: .uncle',
|
|
'autoprefixer: <css input>:149:3: Autoprefixer cannot find ' +
|
|
'a grid-template containing the duplicate grid-area ' +
|
|
'"child" with full selector matching: .uncle',
|
|
'autoprefixer: <css input>:154:3: Autoprefixer cannot find ' +
|
|
'a grid-template containing the duplicate grid-area ' +
|
|
'"child" with full selector matching: .grand-parent .uncle-second',
|
|
'autoprefixer: <css input>:159:3: Autoprefixer cannot find ' +
|
|
'a grid-template containing the duplicate grid-area ' +
|
|
'"child" with full selector matching: .grand-parent .uncle-second',
|
|
'autoprefixer: <css input>:164:3: Autoprefixer cannot find ' +
|
|
'a grid-template containing the duplicate grid-area ' +
|
|
'"child" with full selector matching: .grand-parent .father.uncle',
|
|
'autoprefixer: <css input>:169:3: Autoprefixer cannot find ' +
|
|
'a grid-template containing the duplicate grid-area ' +
|
|
'"child" with full selector matching: .grand-parent.uncle .father'
|
|
]
|
|
)
|
|
})
|
|
|
|
test('should preserve @media rules with grid-area', () => {
|
|
let input = read('grid-area-media-sequence')
|
|
let output = read('grid-area-media-sequence.out')
|
|
let instance = prefixer('grid-area')
|
|
let result = postcss([instance]).process(input)
|
|
equal(result.css, output)
|
|
})
|
|
|
|
test('should merge complex duplicate grid-area rules successfully', () => {
|
|
let input = read('grid-areas-duplicate-complex')
|
|
let output = read('grid-areas-duplicate-complex.out')
|
|
let instance = prefixer('grid-area')
|
|
let result = postcss([instance]).process(input)
|
|
equal(result.css, output)
|
|
})
|
|
|
|
test('resets grid-area spans when overriding a broader area', () => {
|
|
let input = `/* autoprefixer grid: autoplace */
|
|
body {
|
|
display: grid;
|
|
grid-template:
|
|
"other other"
|
|
"one two";
|
|
}
|
|
|
|
body > * {
|
|
grid-area: other;
|
|
}
|
|
|
|
body > .one {
|
|
grid-area: one;
|
|
}
|
|
|
|
body > .two {
|
|
grid-area: two;
|
|
}`
|
|
let output = `/* autoprefixer grid: autoplace */
|
|
body {
|
|
display: -ms-grid;
|
|
display: grid;
|
|
-ms-grid-rows: auto;
|
|
grid-template:
|
|
"other other"
|
|
"one two";
|
|
}
|
|
|
|
body > * {
|
|
-ms-grid-row: 1;
|
|
-ms-grid-column: 1;
|
|
-ms-grid-column-span: 2;
|
|
grid-area: other;
|
|
}
|
|
|
|
body > .one {
|
|
-ms-grid-row: 2;
|
|
-ms-grid-column: 1;
|
|
-ms-grid-column-span: 1;
|
|
grid-area: one;
|
|
}
|
|
|
|
body > .two {
|
|
-ms-grid-row: 2;
|
|
-ms-grid-column: 2;
|
|
-ms-grid-column-span: 1;
|
|
grid-area: two;
|
|
}`
|
|
let result = postcss([prefixer('grid-area')]).process(input)
|
|
equal(result.css, output)
|
|
})
|
|
|
|
test('sets source for grid nodes', () => {
|
|
for (let name of [
|
|
'grid-template-areas',
|
|
'grid-media-rules',
|
|
'grid-autoplacement'
|
|
]) {
|
|
let result = postcss([prefixer('grid')]).process(read(name), {
|
|
from: name + '.css',
|
|
map: { inline: false }
|
|
})
|
|
equal(result.map.toJSON().sources, [name + '.css'])
|
|
}
|
|
})
|
|
|
|
test('ignores values for CSS3PIE props', () => {
|
|
let css = read('pie')
|
|
equal(postcss([compiler]).process(css).css, css)
|
|
})
|
|
|
|
test('add prefix for backface-visibility for Safari 9', () => {
|
|
let input = 'a{ backface-visibility: hidden; transform-style: preserve-3d }'
|
|
let ap = autoprefixer({
|
|
flexbox: false,
|
|
overrideBrowserslist: ['Safari 9']
|
|
})
|
|
equal(
|
|
postcss([ap]).process(input).css,
|
|
'a{ ' +
|
|
'-webkit-backface-visibility: hidden; ' +
|
|
'backface-visibility: hidden; ' +
|
|
'transform-style: preserve-3d }'
|
|
)
|
|
})
|
|
|
|
test('supports text-decoration', () => {
|
|
let input = read('text-decoration')
|
|
let output = read('text-decoration.out')
|
|
let instance = prefixer('text-decoration')
|
|
let result = postcss([instance]).process(input)
|
|
|
|
equal(universalizer(result.css), universalizer(output))
|
|
equal(
|
|
result.warnings().map(i => i.toString()),
|
|
[
|
|
'autoprefixer: <css input>:32:3: Replace text-decoration-skip: ink ' +
|
|
'to text-decoration-skip-ink: auto, because spec had been changed'
|
|
]
|
|
)
|
|
})
|
|
|
|
test('supports text-decoration shorthand', () => {
|
|
let input = read('text-decoration')
|
|
let output = read('text-decoration.shorthand.out')
|
|
let instance = prefixer('text-decoration-shorthand')
|
|
let result = postcss([instance]).process(input)
|
|
|
|
equal(universalizer(result.css), universalizer(output))
|
|
})
|
|
|
|
test('supports -webkit-line-clamp', () => {
|
|
let input = read('webkit-line-clamp')
|
|
let output = read('webkit-line-clamp.out')
|
|
let result = postcss([cleaner]).process(input)
|
|
|
|
equal(universalizer(result.css), universalizer(output))
|
|
equal(result.warnings().length, 0)
|
|
})
|
|
|
|
test('supports latest Firefox stretch', () => {
|
|
let input = read('intrinsic')
|
|
let output = read('intrinsic.ff')
|
|
let result = postcss([
|
|
autoprefixer({ overrideBrowserslist: 'firefox 90' })
|
|
]).process(input)
|
|
equal(result.css, output)
|
|
equal(result.warnings().length, 2)
|
|
})
|
|
|
|
test.run()
|