/* eslint-disable no-underscore-dangle */ import expect from 'expect.js' import {stripIndent} from 'common-tags' import jssExtend from 'jss-plugin-extend' import {create} from 'jss' import sinon from 'sinon' import functionPlugin from 'jss-plugin-rule-value-function' import nested from '.' const settings = { createGenerateId: () => rule => `${rule.key}-id` } describe('jss-plugin-nested', () => { let jss let spy beforeEach(() => { spy = sinon.spy(console, 'warn') jss = create(settings).use(nested()) }) afterEach(() => { console.warn.restore() }) describe('nesting with space', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet({ a: { float: 'left', '& b': {float: 'left'} } }) }) it('should add rules', () => { expect(sheet.getRule('a')).to.not.be(undefined) expect(sheet.getRule('.a-id b')).to.not.be(undefined) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be('.a-id {\n float: left;\n}\n.a-id b {\n float: left;\n}') }) }) describe('nesting without space', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet({ a: { float: 'left', '&b': {float: 'left'} } }) }) it('should add rules', () => { expect(sheet.getRule('a')).to.not.be(undefined) expect(sheet.getRule('.a-idb')).to.not.be(undefined) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be('.a-id {\n float: left;\n}\n.a-idb {\n float: left;\n}') }) }) describe('multi nesting', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet({ a: { float: 'left', '&b': {float: 'left'}, '& c': {float: 'left'} } }) }) it('should add rules', () => { expect(sheet.getRule('a')).to.not.be(undefined) expect(sheet.getRule('.a-idb')).to.not.be(undefined) expect(sheet.getRule('.a-id c')).to.not.be(undefined) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be( '.a-id {\n' + ' float: left;\n' + '}\n' + '.a-idb {\n' + ' float: left;\n' + '}\n' + '.a-id c {\n' + ' float: left;\n' + '}' ) }) }) describe('multi nesting in one selector', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet({ a: { float: 'left', '&b, &c': {float: 'left'} } }) }) it('should add rules', () => { expect(sheet.getRule('a')).to.not.be(undefined) expect(sheet.getRule('.a-idb, .a-idc')).to.not.be(undefined) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be( '.a-id {\n float: left;\n}\n.a-idb, .a-idc {\n float: left;\n}' ) }) }) describe('.addRules()', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet({ a: { height: '1px' } }) sheet.addRules({ b: { height: '2px', '& c': { height: '3px' } } }) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be( '.a-id {\n' + ' height: 1px;\n' + '}\n' + '.b-id {\n' + ' height: 2px;\n' + '}\n' + '.b-id c {\n' + ' height: 3px;\n' + '}' ) }) }) describe('nesting in a conditional', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet({ a: { color: 'green' }, '@media': { a: { '&:hover': {color: 'red'} } } }) }) it('should add rules', () => { expect(sheet.getRule('a')).to.not.be(undefined) expect(sheet.getRule('@media')).to.not.be(undefined) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be( '.a-id {\n' + ' color: green;\n' + '}\n' + '@media {\n' + ' .a-id:hover {\n' + ' color: red;\n' + ' }\n' + '}' ) }) }) describe('nesting a conditional rule inside a regular rule', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet({ a: { color: 'green', '@media': { width: '200px' } }, b: { color: 'red' } }) }) it('should add rules', () => { expect(sheet.getRule('a')).to.not.be(undefined) expect(sheet.getRule('@media')).to.not.be(undefined) expect(sheet.getRule('b')).to.not.be(undefined) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be( '.a-id {\n' + ' color: green;\n' + '}\n' + '@media {\n' + ' .a-id {\n' + ' width: 200px;\n' + ' }\n' + '}\n' + '.b-id {\n' + ' color: red;\n' + '}' ) }) }) describe('nesting a conditional rule inside of a nested rule', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet({ a: { '&:hover': { color: 'red', '@media': { color: 'green' } } } }) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be(stripIndent` .a-id:hover { color: red; } @media { .a-id:hover { color: green; } } `) }) }) describe('order of nested conditionals', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet({ a: { '@media a': { color: 'red' }, '@media b': { color: 'green' } } }) }) it('should add rules', () => { expect(sheet.getRule('@media a')).to.not.be(undefined) expect(sheet.getRule('@media b')).to.not.be(undefined) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be( '@media a {\n' + ' .a-id {\n' + ' color: red;\n' + ' }\n' + '}\n' + '@media b {\n' + ' .a-id {\n' + ' color: green;\n' + ' }\n' + '}' ) }) }) describe('adding a rule with a conditional rule', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet() sheet.addRule('a', { color: 'green', '@media': { width: '200px' } }) }) it('should add rules', () => { expect(sheet.getRule('a')).to.not.be(undefined) expect(sheet.getRule('@media')).to.not.be(undefined) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be( '.a-id {\n' + ' color: green;\n' + '}\n' + '@media {\n' + ' .a-id {\n' + ' width: 200px;\n' + ' }\n' + '}' ) }) }) describe('do not merge nested conditional to container conditional with existing rule', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet({ a: { color: 'green', '@media': { width: '200px' }, '@media large': { width: '300px' } }, '@media': { b: { color: 'blue' } }, c: { color: 'red' } }) }) it('should add rules', () => { expect(sheet.getRule('a')).to.not.be(undefined) expect(sheet.getRule('@media')).to.not.be(undefined) expect(sheet.getRule('c')).to.not.be(undefined) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be( '.a-id {\n' + ' color: green;\n' + '}\n' + '@media {\n' + ' .a-id {\n' + ' width: 200px;\n' + ' }\n' + '}\n' + '@media large {\n' + ' .a-id {\n' + ' width: 300px;\n' + ' }\n' + '}\n' + '@media {\n' + ' .b-id {\n' + ' color: blue;\n' + ' }\n' + '}\n' + '.c-id {\n' + ' color: red;\n' + '}' ) }) }) describe('warnings', () => { it('should warn when referenced rule is not found', () => { jss.createStyleSheet({ a: { '& $b': {float: 'left'} } }) expect(spy.callCount).to.be(1) expect( spy.calledWithExactly( 'Warning: [JSS] Could not find the referenced rule "b" in ".a-id {\n & $b: [object Object];\n}".' ) ).to.be(true) }) }) describe('local refs', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet({ a: { float: 'left', '& $b': {float: 'left'}, '& $b-warn': {float: 'right'} }, b: { color: 'red' }, 'b-warn': { color: 'orange' } }) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be( '.a-id {\n' + ' float: left;\n' + '}\n' + '.a-id .b-id {\n' + ' float: left;\n' + '}\n' + '.a-id .b-warn-id {\n' + ' float: right;\n' + '}\n' + '.b-id {\n' + ' color: red;\n' + '}\n' + '.b-warn-id {\n' + ' color: orange;\n' + '}' ) }) }) describe.skip('nesting conditionals in combination with extend plugin', () => { let sheet beforeEach(() => { const localJss = create(settings).use(jssExtend(), nested()) sheet = localJss.createStyleSheet({ button: { color: 'green', 'background-color': 'aqua', '@media': { width: '200px' } }, redButton: { extend: 'button', color: 'red' } }) }) it('should add rules', () => { expect(sheet.getRule('button')).to.not.be(undefined) expect(sheet.getRule('@media')).to.not.be(undefined) expect(sheet.getRule('redButton')).to.not.be(undefined) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be( '.button-id {\n' + ' color: green;\n' + ' background-color: aqua;\n' + '}\n' + '@media {\n' + ' .button-id {\n' + ' width: 200px;\n' + ' }\n' + '}\n' + '.redButton-id {\n' + ' color: red;\n' + ' background-color: aqua;\n' + '}\n' + '@media {\n' + ' .redButton-id {\n' + ' width: 200px;\n' + ' }\n' + '}' ) }) }) describe('deep nesting', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet({ button: { color: 'black', '& .a': { color: 'red', '& .c': { color: 'gold' } } } }) }) it('should add rules', () => { expect(sheet.getRule('button')).to.not.be(undefined) expect(sheet.getRule('.button-id .a')).to.not.be(undefined) expect(sheet.getRule('.button-id .a .c')).to.not.be(undefined) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be( '.button-id {\n' + ' color: black;\n' + '}\n' + '.button-id .a {\n' + ' color: red;\n' + '}\n' + '.button-id .a .c {\n' + ' color: gold;\n' + '}' ) }) }) describe('deep nesting with multiple nestings in one selector', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet({ button: { color: 'black', '& .a, .b': { color: 'red', '& .c, &:hover': { color: 'gold' } } } }) }) it('should add rules', () => { expect(sheet.getRule('button')).to.not.be(undefined) expect(sheet.getRule('.button-id .a, .button-id .b')).to.not.be(undefined) expect( sheet.getRule( '.button-id .a .c, .button-id .a:hover, .button-id .b .c, .button-id .b:hover' ) ).to.not.be(undefined) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be( '.button-id {\n' + ' color: black;\n' + '}\n' + '.button-id .a, .button-id .b {\n' + ' color: red;\n' + '}\n' + '.button-id .a .c, .button-id .a:hover, ' + '.button-id .b .c, .button-id .b:hover {\n' + ' color: gold;\n' + '}' ) }) }) describe('support & at any position', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet({ a: { 'input:focus + &': { color: 'red' } } }) }) it('should generate correct CSS', () => { expect(sheet.toString()).to.be('input:focus + .a-id {\n color: red;\n}') }) }) describe('function values', () => { let sheet beforeEach(() => { const localJss = create(settings).use(nested(), functionPlugin()) sheet = localJss.createStyleSheet({ a: { color: ({color}) => color, '&:hover': { color: ({color}) => color } } }) }) it('should generate color red', () => { sheet.update({color: 'red'}) expect(sheet.toString()).to.be(stripIndent` .a-id { color: red; } .a-id:hover { color: red; } `) }) it('should generate color green', () => { sheet.update({color: 'green'}) expect(sheet.toString()).to.be(stripIndent` .a-id { color: green; } .a-id:hover { color: green; } `) }) }) describe('nest rules inside media query', () => { let sheet beforeEach(() => { sheet = jss.createStyleSheet({ a: {}, b: { '@media (min-width: 576px)': { '& $a': { margin: '15px' } } } }) }) it('should generate nested rules inside media queries', () => { expect(sheet.toString()).to.be(stripIndent` @media (min-width: 576px) { .b-id .a-id { margin: 15px; } } `) }) }) })