require File.expand_path(File.dirname(__FILE__) + '/spec_helper') require 'digest/md5' describe Compass::Sprites do before :each do create_sprite_temp file = StringIO.new("images_path = #{@images_tmp_path.inspect}\n") Compass.add_configuration(file, "sprite_config") Compass.configure_sass_plugin! end after :each do clean_up_sprites end def map_location(file) Dir.glob(File.join(@images_tmp_path, file)).first end def image_size(file) IO.read(map_location(file))[0x10..0x18].unpack('NN') end def image_md5(file) md5 = Digest::MD5.new md5.update IO.read(map_location(file)) md5.hexdigest end def render(scss) scss = %Q(@import "compass"; #{scss}) options = Compass.sass_engine_options options[:line_comments] = false options[:style] = :expanded options[:syntax] = :scss css = Sass::Engine.new(scss, options).render # reformat to fit result of heredoc: " #{css.gsub('@charset "UTF-8";', '').gsub(/\n/, "\n ").strip}\n" end #Callbacks describe 'callbacks' do it "should fire on_sprite_saved" do saved = false path = nil Compass.configuration.on_sprite_saved {|filepath| path = filepath; saved = true } render <<-SCSS @import "squares/*.png"; @include all-squares-sprites; SCSS saved.should eq true path.should be_kind_of String end it "should fire on_sprite_generated" do saved = false sprite_data = nil Compass.configuration.on_sprite_generated {|data| sprite_data = data; saved = true } render <<-SCSS @import "squares/*.png"; @include all-squares-sprites; SCSS sprite_data.should be_kind_of ChunkyPNG::Image saved.should eq true end end # DEFAULT USAGE: it "should generate sprite classes" do css = render <<-SCSS @import "squares/*.png"; @include all-squares-sprites; SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { background: url('/squares-161c60ad78.png') no-repeat; } .squares-ten-by-ten { background-position: 0 0; } .squares-twenty-by-twenty { background-position: 0 -10px; } CSS image_size('squares-*.png').should == [20, 30] image_md5('squares-*.png').should == 'fcc93d7b279c2ad6898fbca49cbd01e1' end it "should generate sprite classes with dimensions" do css = render <<-SCSS $squares-sprite-dimensions: true; @import "squares/*.png"; @include all-squares-sprites; SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { background: url('/squares-161c60ad78.png') no-repeat; } .squares-ten-by-ten { background-position: 0 0; height: 10px; width: 10px; } .squares-twenty-by-twenty { background-position: 0 -10px; height: 20px; width: 20px; } CSS image_size('squares-*.png').should == [20, 30] end it "should provide sprite mixin" do css = render <<-SCSS @import "squares/*.png"; .cubicle { @include squares-sprite("ten-by-ten"); } .large-cube { @include squares-sprite("twenty-by-twenty", true); } SCSS css.should == <<-CSS .squares-sprite, .cubicle, .large-cube { background: url('/squares-161c60ad78.png') no-repeat; } .cubicle { background-position: 0 0; } .large-cube { background-position: 0 -10px; height: 20px; width: 20px; } CSS image_size('squares-*.png').should == [20, 30] end # CUSTOMIZATIONS: it "should be possible to change the base class" do css = render <<-SCSS $squares-sprite-base-class: ".circles"; @import "squares/*.png"; SCSS css.should == <<-CSS .circles { background: url('/squares-161c60ad78.png') no-repeat; } CSS image_size('squares-*.png').should == [20, 30] end it "should calculate the spacing between images but not before first image" do css = render <<-SCSS $squares-ten-by-ten-spacing: 33px; @import "squares/*.png"; @include all-squares-sprites; SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { background: url('/squares-89450808af.png') no-repeat; } .squares-ten-by-ten { background-position: 0 0; } .squares-twenty-by-twenty { background-position: 0 -43px; } CSS image_size('squares-*.png').should == [20, 63] end it "should calculate the spacing between images" do css = render <<-SCSS $squares-twenty-by-twenty-spacing: 33px; @import "squares/*.png"; @include all-squares-sprites; SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { background: url('/squares-673837183a.png') no-repeat; } .squares-ten-by-ten { background-position: 0 0; } .squares-twenty-by-twenty { background-position: 0 -43px; } CSS image_size('squares-*.png').should == [20, 63] end it "should calculate the maximum spacing between images" do css = render <<-SCSS $squares-ten-by-ten-spacing: 44px; $squares-twenty-by-twenty-spacing: 33px; @import "squares/*.png"; @include all-squares-sprites; SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { background: url('/squares-1cd84c9068.png') no-repeat; } .squares-ten-by-ten { background-position: 0 0; } .squares-twenty-by-twenty { background-position: 0 -54px; } CSS image_size('squares-*.png').should == [20, 74] end it "should calculate the maximum spacing between images in reversed order" do css = render <<-SCSS $squares-ten-by-ten-spacing: 33px; $squares-twenty-by-twenty-spacing: 44px; @import "squares/*.png"; @include all-squares-sprites; SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { background: url('/squares-f25b7090ca.png') no-repeat; } .squares-ten-by-ten { background-position: 0 0; } .squares-twenty-by-twenty { background-position: 0 -54px; } CSS image_size('squares-*.png').should == [20, 74] end it "should calculate the default spacing between images" do css = render <<-SCSS $squares-spacing: 22px; @import "squares/*.png"; @include all-squares-sprites; SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { background: url('/squares-d66bf24bab.png') no-repeat; } .squares-ten-by-ten { background-position: 0 0; } .squares-twenty-by-twenty { background-position: 0 -32px; } CSS image_size('squares-*.png').should == [20, 52] end it "should use position adjustments in functions" do css = render <<-SCSS $squares: sprite-map("squares/*.png", $position: 100%); .squares-sprite { background: $squares no-repeat; } .adjusted-percentage { background-position: sprite-position($squares, ten-by-ten, 100%); } .adjusted-px-1 { background-position: sprite-position($squares, ten-by-ten, 4px); } .adjusted-px-2 { background-position: sprite-position($squares, twenty-by-twenty, -3px, 2px); } SCSS css.should == <<-CSS .squares-sprite { background: url('/squares-8e490168dd.png') no-repeat; } .adjusted-percentage { background-position: 100% 0; } .adjusted-px-1 { background-position: -6px 0; } .adjusted-px-2 { background-position: -3px -8px; } CSS image_size('squares-*.png').should == [20, 30] image_md5('squares-*.png').should == '652b67f5e9092520d6f26caae7e18012' end it "should use position adjustments in mixins" do css = render <<-SCSS $squares-position: 100%; @import "squares/*.png"; .adjusted-percentage { @include squares-sprite("ten-by-ten", $offset-x: 100%); } .adjusted-px-1 { @include squares-sprite("ten-by-ten", $offset-x: 4px); } .adjusted-px-2 { @include squares-sprite("twenty-by-twenty", $offset-x: -3px, $offset-y: 2px); } SCSS css.should == <<-CSS .squares-sprite, .adjusted-percentage, .adjusted-px-1, .adjusted-px-2 { background: url('/squares-8e490168dd.png') no-repeat; } .adjusted-percentage { background-position: 100% 0; } .adjusted-px-1 { background-position: -6px 0; } .adjusted-px-2 { background-position: -3px -8px; } CSS image_size('squares-*.png').should == [20, 30] image_md5('squares-*.png').should == '652b67f5e9092520d6f26caae7e18012' end it "should repeat the image" do css = render <<-SCSS $squares-repeat: repeat; @import "squares/*.png"; @include all-squares-sprites; SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { background: url('/squares-a5550fd132.png') no-repeat; } .squares-ten-by-ten { background-position: 0 0; } .squares-twenty-by-twenty { background-position: 0 -10px; } CSS image_size('squares-*.png').should == [20, 30] image_md5('squares-*.png').should == '94abae8440f1b58617f52920b70aaed2' end it "should allow the position of a sprite to be specified in absolute pixels" do css = render <<-SCSS $squares-ten-by-ten-position: 10px; $squares-twenty-by-twenty-position: 10px; @import "squares/*.png"; @include all-squares-sprites; SCSS css.should == <<-CSS .squares-sprite, .squares-ten-by-ten, .squares-twenty-by-twenty { background: url('/squares-89a274044e.png') no-repeat; } .squares-ten-by-ten { background-position: -10px 0; } .squares-twenty-by-twenty { background-position: -10px -10px; } CSS image_size('squares-*.png').should == [30, 30] image_md5('squares-*.png').should == '2fb19ef9c83018c93c6f147af3a56cb2' end it "should provide a nice errors for lemonade's old users" do proc do render <<-SCSS .squares { background: sprite-url("squares/*.png") no-repeat; } SCSS end.should raise_error Sass::SyntaxError, %q(The first argument to sprite-url() must be a sprite map. See http://beta.compass-style.org/help/tutorials/spriting/ for more information.) proc do render <<-SCSS .squares { background: sprite-image("squares/twenty-by-twenty.png") no-repeat; } SCSS end.should raise_error Sass::SyntaxError, %q(The sprite-image() function has been replaced by sprite(). See http://beta.compass-style.org/help/tutorials/spriting/ for more information.) proc do render <<-SCSS @import "squares/*.png"; .squares { background: sprite-position("squares/twenty-by-twenty.png") no-repeat; } SCSS end.should raise_error Sass::SyntaxError, %q(The first argument to sprite-position() must be a sprite map. See http://beta.compass-style.org/help/tutorials/spriting/ for more information.) end it "should work even if @import is missing" do actual_css = render <<-SCSS .squares { background: sprite(sprite-map("squares/*.png"), twenty-by-twenty) no-repeat; } SCSS actual_css.should == <<-CSS .squares { background: url('/squares-145869726f.png') 0 -10px no-repeat; } CSS end it "should calculate corret sprite demsions when givin spacing via issue#253" do css = render <<-SCSS $squares-spacing: 10px; @import "squares/*.png"; .foo { @include sprite-background-position($squares-sprites, "twenty-by-twenty"); } .bar { @include sprite-background-position($squares-sprites, "ten-by-ten"); } SCSS image_size('squares-*.png').should == [20, 40] css.should == <<-CSS .squares-sprite { background: url('/squares-e3c68372d9.png') no-repeat; } .foo { background-position: 0 -20px; } .bar { background-position: 0 0; } CSS end it "should render corret sprite with css selectors via issue#248" do css = render <<-SCSS @import "selectors/*.png"; @include all-selectors-sprites; SCSS css.should == <<-CSS .selectors-sprite, .selectors-ten-by-ten { background: url('/selectors-edfef809e2.png') no-repeat; } .selectors-ten-by-ten { background-position: 0 0; } .selectors-ten-by-ten:hover, .selectors-ten-by-ten.ten-by-ten_hover, .selectors-ten-by-ten.ten-by-ten-hover { background-position: 0 -20px; } .selectors-ten-by-ten:target, .selectors-ten-by-ten.ten-by-ten_target, .selectors-ten-by-ten.ten-by-ten-target { background-position: 0 -30px; } .selectors-ten-by-ten:active, .selectors-ten-by-ten.ten-by-ten_active, .selectors-ten-by-ten.ten-by-ten-active { background-position: 0 -10px; } CSS end it "should render corret sprite with css selectors via magic mixin" do css = render <<-SCSS @import "selectors/*.png"; a { @include selectors-sprite(ten-by-ten) } SCSS css.should == <<-CSS .selectors-sprite, a { background: url('/selectors-edfef809e2.png') no-repeat; } a { background-position: 0 0; } a:hover, a.ten-by-ten_hover, a.ten-by-ten-hover { background-position: 0 -20px; } a:target, a.ten-by-ten_target, a.ten-by-ten-target { background-position: 0 -30px; } a:active, a.ten-by-ten_active, a.ten-by-ten-active { background-position: 0 -10px; } CSS end it "should raise error on filenames that are not valid sass syntax" do lambda do render <<-SCSS @import "prefix/*.png"; a { @include squares-sprite(20-by-20); } SCSS end.should raise_error Compass::Error end it "should generate sprite with bad repeat-x dimensions" do css = render <<-SCSS $ko-starbg26x27-repeat: repeat-x; @import "ko/*.png"; @include all-ko-sprites; SCSS css.should == <<-CSS .ko-sprite, .ko-default_background, .ko-starbg26x27 { background: url('/ko-cc3f80660d.png') no-repeat; } .ko-default_background { background-position: 0 0; } .ko-starbg26x27 { background-position: 0 -128px; } CSS end end