cartodb-4.42/spec/requests/carto/api/layer_presenter_spec.rb

1220 lines
46 KiB
Ruby
Raw Normal View History

2024-04-06 13:25:13 +08:00
require_relative '../../../spec_helper'
require_relative '../../../../app/controllers/carto/api/layer_presenter'
require_relative '../../api/json/layer_presenter_shared_examples'
describe "Carto::Api::LayersController - Layer Model" do
it_behaves_like 'layer presenters', Carto::Api::LayerPresenter, ::Layer
end
describe "Carto::Api::LayersController - Carto::Layer" do
it_behaves_like 'layer presenters', Carto::Api::LayerPresenter, Carto::Layer
end
describe Carto::Api::LayerPresenter do
def presenter_with_style_properties(layer)
Carto::Api::LayerPresenter.new(layer, with_style_properties: true)
end
describe 'wizard_properties migration to style_properties' do
def wizard_properties(type: 'polygon', properties: {})
{ "type" => type, 'properties' => properties }
end
def build_layer_with_wizard_properties(properties)
FactoryGirl.build(:carto_layer, options: { 'wizard_properties' => properties })
end
it "doesn't autogenerate `style_properties` if `wizard_properties` isn't present but it's not requested" do
layer = build_layer_with_wizard_properties(wizard_properties)
poro_options = Carto::Api::LayerPresenter.new(layer).to_poro['options']
poro_options['wizard_properties'].should_not be_nil
poro_options['style_properties'].should be_nil
end
it "autogenerates `style_properties` based on `wizard_properties` if it isn't present and it's requested" do
layer = build_layer_with_wizard_properties(wizard_properties)
poro_options = presenter_with_style_properties(layer).to_poro['options']
poro_options['wizard_properties'].should_not be_nil
style_properties = poro_options['style_properties']
style_properties.should_not be_nil
style_properties['autogenerated'].should be_true
end
it "autogenerates `style_properties` based on `wizard_properties` if it is present but autogenerated" do
layer = build_layer_with_wizard_properties(wizard_properties)
layer.options['style_properties'] = { 'autogenerated' => true, 'wadus' => 'wadus' }
poro_options = presenter_with_style_properties(layer).to_poro['options']
poro_options['wizard_properties'].should_not be_nil
style_properties = poro_options['style_properties']
style_properties.should_not be_nil
style_properties['autogenerated'].should be_true
style_properties['type'].should_not be_nil
style_properties['wadus'].should be_nil
end
it "doesn't autogenerate `style_properties` based on `wizard_properties` if it is present and not autogenerated" do
layer = build_layer_with_wizard_properties(wizard_properties)
layer.options['style_properties'] = { 'autogenerated' => false, 'wadus' => 'wadus' }
poro_options = presenter_with_style_properties(layer).to_poro['options']
poro_options['wizard_properties'].should_not be_nil
style_properties = poro_options['style_properties']
style_properties.should_not be_nil
style_properties['autogenerated'].should be_false
style_properties['wadus'].should eq 'wadus'
end
it "doesn't autogenerate `style_properties` if `wizard_properties` is not present or is empty" do
layer = build_layer_with_wizard_properties(wizard_properties)
layer.options.delete('wizard_properties')
poro_options = presenter_with_style_properties(layer).to_poro['options']
poro_options['wizard_properties'].should be_nil
style_properties = poro_options['style_properties']
style_properties.should be_nil
layer = build_layer_with_wizard_properties(wizard_properties)
layer.options['wizard_properties'] = nil
poro_options = presenter_with_style_properties(layer).to_poro['options']
poro_options['wizard_properties'].should be_nil
style_properties = poro_options['style_properties']
style_properties.should be_nil
layer = build_layer_with_wizard_properties({})
poro_options = presenter_with_style_properties(layer).to_poro['options']
poro_options['wizard_properties'].should_not be_nil
style_properties = poro_options['style_properties']
style_properties.should be_nil
end
it "doesn't autogenerate `style_properties` if type is not mapped" do
unknown_type = 'wadus'
layer = build_layer_with_wizard_properties('type' => unknown_type)
poro_options = presenter_with_style_properties(layer).to_poro['options']
poro_options['wizard_properties']['type'].should eq unknown_type
poro_options['style_properties'].should be_nil
end
describe 'options migration' do
it 'migrates tile_style_custom to cartocss_custom (defaults to false)' do
layer = build_layer_with_wizard_properties(wizard_properties(properties: {}))
layer.options.delete('tile_style_custom')
presenter_with_style_properties(layer).to_poro['options']['cartocss_custom'].should eq false
layer.options['tile_style_custom'] = true
presenter_with_style_properties(layer).to_poro['options']['cartocss_custom'].should eq true
layer.options['tile_style_custom'] = false
presenter_with_style_properties(layer).to_poro['options']['cartocss_custom'].should eq false
end
it 'migrates tile_style_history to cartocss_history (defaults to [])' do
layer = build_layer_with_wizard_properties(wizard_properties(properties: {}))
layer.options.delete('tile_style_history')
presenter_with_style_properties(layer).to_poro['options']['cartocss_history'].should eq []
layer.options['tile_style_history'] = ['wadus', 'wadus2']
presenter_with_style_properties(layer).to_poro['options']['cartocss_history'].should eq ['wadus', 'wadus2']
layer.options['tile_style_history'] = []
presenter_with_style_properties(layer).to_poro['options']['cartocss_history'].should eq []
end
end
describe 'simple' do
it 'is generated from several types' do
types_generating_simple = %w(polygon bubble choropleth category)
types_generating_simple.each do |type_generating_simple|
layer = build_layer_with_wizard_properties('type' => type_generating_simple)
poro_options = presenter_with_style_properties(layer).to_poro['options']
poro_options['wizard_properties']['type'].should eq type_generating_simple
style_properties = poro_options['style_properties']
style_properties['type'].should eq 'simple'
end
end
it 'does not have animated' do
layer = build_layer_with_wizard_properties(wizard_properties(properties: {}))
poro_options = presenter_with_style_properties(layer).to_poro['options']
animated = poro_options['style_properties']['properties']['animated']
animated.should be_nil
end
it 'has defaults for labels' do
layer = build_layer_with_wizard_properties(wizard_properties(properties: {}))
poro_options = presenter_with_style_properties(layer).to_poro['options']
labels = poro_options['style_properties']['properties']['labels']
labels.should_not be_nil
labels['enabled'].should eq false
labels['attribute'].should be_nil
labels['font'].should eq 'DejaVu Sans Book'
fill = labels['fill']
fill['size']['fixed'].should eq 10
fill_color = fill['color']
fill_color['fixed'].should eq '#000'
fill_color['opacity'].should eq 1
halo = labels['halo']
halo['size']['fixed'].should eq 1
halo_color = halo['color']
halo_color['fixed'].should eq '#111'
halo_color['opacity'].should eq 1
labels['offset'].should eq(-10)
labels['overlap'].should eq true
labels['placement'].should eq 'point'
end
it 'defaults missing labels attributes' do
properties = {
"text-face-name" => "whatever"
}
layer = build_layer_with_wizard_properties(wizard_properties(properties: properties))
poro_options = presenter_with_style_properties(layer).to_poro['options']
labels = poro_options['style_properties']['properties']['labels']
labels.should_not be_nil
labels['enabled'].should eq false
labels['font'].should eq 'whatever'
labels['attribute'].should be_nil
fill = labels['fill']
fill['size']['fixed'].should eq 10
fill_color = fill['color']
fill_color['fixed'].should eq '#000'
fill_color['opacity'].should eq 1
halo = labels['halo']
halo['size']['fixed'].should eq 1
halo_color = halo['color']
halo_color['fixed'].should eq '#111'
halo_color['opacity'].should eq 1
labels['offset'].should eq(-10)
labels['overlap'].should eq true
labels['placement'].should eq 'point'
end
end
describe 'wizard migration' do
COLOR = '#fabada'.freeze
COLOR_1 = "#FACADA".freeze
COLOR_2 = "#TACADA".freeze
OPACITY = 0.3
describe 'polygon' do
describe 'polygon' do
let(:marker_width) { 10 }
let(:polygon_wizard_properties) do
{
"type" => "polygon",
"properties" =>
{
"marker-width" => marker_width,
"marker-fill" => "#FF6600",
"marker-opacity" => 0.9,
"marker-allow-overlap" => true,
"marker-placement" => "point",
"marker-type" => "ellipse",
"marker-line-width" => 1,
"marker-line-color" => "#FFF",
"marker-line-opacity" => 1,
"marker-comp-op" => "none",
"text-name" => "None",
"text-face-name" => "DejaVu Sans Book",
"text-size" => 10,
"text-fill" => "#000",
"text-halo-fill" => "#FFF",
"text-halo-radius" => 1,
"text-dy" => -10,
"text-allow-overlap" => true,
"text-placement-type" => "dummy",
"text-label-position-tolerance" => 0,
"text-placement" => "point",
"geometry_type" => "point"
}
}
end
it 'sets fill size from marker-width' do
layer = build_layer_with_wizard_properties(polygon_wizard_properties)
options = presenter_with_style_properties(layer).to_poro['options']
properties = options['style_properties']['properties']
fill_size = properties['fill']['size']
fill_size['fixed'].should eq marker_width
end
it 'ignores property' do
polygon_wizard_properties['properties']['property'] = 'wadus_property'
layer = build_layer_with_wizard_properties(polygon_wizard_properties)
options = presenter_with_style_properties(layer).to_poro['options']
properties = options['style_properties']['properties']
JSON.dump(properties).should_not include 'wadus_property'
end
end
describe 'polygon-fill, marker-fill become "color fill" structure' do
it 'setting opacity 1 if unknown' do
%w(polygon-fill marker-fill).each do |property|
properties = { property => COLOR }
layer = build_layer_with_wizard_properties(wizard_properties(properties: properties))
options = presenter_with_style_properties(layer).to_poro['options']
options['wizard_properties']['properties'][property].should eq COLOR
fill_color = options['style_properties']['properties']['fill']['color']
fill_color.should eq('fixed' => COLOR, 'opacity' => 1)
end
end
it 'setting related opacity if known' do
%w(polygon marker).each do |property|
properties = { "#{property}-fill" => COLOR, "#{property}-opacity" => OPACITY }
layer = build_layer_with_wizard_properties(wizard_properties(properties: properties))
options = presenter_with_style_properties(layer).to_poro['options']
options['wizard_properties']['properties']["#{property}-fill"].should eq COLOR
fill_color = options['style_properties']['properties']['fill']['color']
fill_color.should eq('fixed' => COLOR, 'opacity' => OPACITY)
end
end
end
end
describe 'cluster' do
let(:query_wrapper) { "with meta ... <%= sql %> ..." }
let(:cluster_options) do
{
"query_wrapper" => query_wrapper,
"wizard_properties" => {
"type" => "cluster",
"properties" => { "method" => "3 Buckets", "marker-fill" => "#FD8D3C" }
}
}
end
before(:each) do
layer = FactoryGirl.build(:carto_layer, options: cluster_options)
@options = presenter_with_style_properties(layer).to_poro['options']
@properties = @options['style_properties']['properties']
end
it 'sets type simple and cartocss_custom to true' do
@options['style_properties']['type'].should eq 'simple'
@options['cartocss_custom'].should eq true
end
it 'sets query_wrapper at sql_wrap' do
@options['sql_wrap'].should eq query_wrapper
end
it 'ignores property' do
cluster_options['wizard_properties']['properties']['property'] = 'wadus_property'
layer = FactoryGirl.build(:carto_layer, options: cluster_options)
options = presenter_with_style_properties(layer).to_poro['options']
properties = options['style_properties']['properties']
JSON.dump(properties).should_not include 'wadus_property'
end
end
describe 'bubble' do
let(:property) { "actor_foll" }
let(:quantile_function) { "Quantile" }
let(:qfunction) { quantile_function }
let(:radius_min) { 10 }
let(:radius_max) { 25 }
let(:marker_comp_op) { "multiply" }
let(:bubble_wizard_properties) do
{
"type" => "bubble",
"properties" =>
{
"property" => property,
"qfunction" => qfunction,
"radius_min" => radius_min,
"radius_max" => radius_max,
"marker-fill" => COLOR,
"marker-opacity" => OPACITY,
"marker-line-width" => 1,
"marker-line-color" => "#FFF",
"marker-line-opacity" => 1,
"zoom" => 4,
"geometry_type" => "point",
"text-placement-type" => "simple",
"text-label-position-tolerance" => 10,
"marker-comp-op" => marker_comp_op
}
}
end
before(:each) do
layer = build_layer_with_wizard_properties(bubble_wizard_properties)
options = presenter_with_style_properties(layer).to_poro['options']
@properties = options['style_properties']['properties']
@fill_color = @properties['fill']['color']
@fill_size = @properties['fill']['size']
end
it 'marker-comp-op becomes blending' do
expect(@properties).to include('blending' => marker_comp_op)
end
describe 'fill size' do
it 'groups radius_min, radius_max into fill size range' do
expect(@fill_size).to include('range' => [radius_min, radius_max])
end
it 'property becomes attribute' do
expect(@fill_size).to include('attribute' => property)
end
it 'bins is set to 10' do
expect(@fill_size).to include('bins' => 10)
end
it 'qfunction becomes quantification, and Quantile is translated to quantiles' do
expect(@fill_size).to include('quantification' => 'quantiles')
end
it 'does not include animated' do
expect(@properties['animated']).to be_nil
end
end
describe 'fill color' do
it 'takes fixed color and opacity from marker-*' do
expect(@fill_color).to include('fixed' => COLOR, 'opacity' => OPACITY)
end
end
end
describe 'choropleth' do
let(:property) { "actor_foll" }
let(:number_of_buckets) { 7 }
let(:qfunction) { "Quantile" }
let(:color_ramp) { "red" }
let(:choropleth_wizard_properties) do
{
"type" => "choropleth",
"properties" =>
{
"property" => property,
"method" => "#{number_of_buckets} Buckets",
"qfunction" => qfunction,
"color_ramp" => color_ramp,
"marker-opacity" => OPACITY,
"marker-width" => 10,
"marker-allow-overlap" => true,
"marker-placement" => "point",
"marker-type" => "ellipse",
"marker-line-width" => 1,
"marker-line-color" => "#FFF",
"marker-line-opacity" => 1,
"marker-comp-op" => "none",
"zoom" => 4,
"geometry_type" => "point"
}
}
end
before(:each) do
layer = build_layer_with_wizard_properties(choropleth_wizard_properties)
options = presenter_with_style_properties(layer).to_poro['options']
@fill_color = options['style_properties']['properties']['fill']['color']
@fill_size = options['style_properties']['properties']['fill']['size']
end
describe 'fill' do
it 'has fixed size 10 by default' do
expect(@fill_size).to include('fixed' => 10)
end
it 'transform color_ramp to color array in range' do
# Commented because this might change soon
# expect(@fill_color).to include('range' => "['#FFEDA0', '#FEB24C', '#F03B20']")
expect(@fill_color).to include('range' => color_ramp)
end
it 'property becomes attribute' do
expect(@fill_color).to include('attribute' => property)
end
it 'method generates bins' do
expect(@fill_color).to include('bins' => number_of_buckets)
end
it 'qfunction becomes quantification, and Quantile is translated to quantiles' do
expect(@fill_color).to include('quantification' => 'quantiles')
end
it 'takes opacity from marker-* or polygon-*' do
expect(@fill_color).to include('opacity' => OPACITY)
end
end
end
describe 'category' do
let(:property) { "aforo" }
let(:opacity) { 0.456 }
let(:marker_line_width) { 1 }
let(:marker_line_color) { "#FFF" }
let(:marker_line_opacity) { 0.7 }
let(:title_1) { 100 }
let(:title_2) { 200 }
let(:line_width) { 0.43 }
let(:line_color) { "#FFA" }
let(:line_opacity) { 0.91 }
let(:category_wizard_properties) do
{
"type" => "category",
"properties" => {
"property" => property,
"zoom" => "15",
"geometry_type" => 'point',
"text-placement-type" => "simple",
"text-label-position-tolerance" => 10,
"categories" => [
{
"title" => title_1,
"title_type" => "number",
"color" => COLOR_1,
"value_type" => "color"
},
{
"title" => title_2,
"title_type" => "number",
"color" => COLOR_2,
"value_type" => "color"
}
]
}
}
end
let(:marker_category_properties) do
{
"marker-width" => 10,
"marker-opacity" => opacity,
"marker-allow-overlap" => true,
"marker-placement" => "point",
"marker-type" => "ellipse",
"marker-line-width" => marker_line_width,
"marker-line-color" => marker_line_color,
"marker-line-opacity" => marker_line_opacity
}
end
let(:line_category_properties) do
{
"line-width" => line_width,
"line-color" => line_color,
"line-opacity" => line_opacity
}
end
describe 'polygon geometry type' do
before(:each) do
properties = category_wizard_properties
properties['properties']['geometry_type'] = 'polygon'
properties['properties'].merge!(line_category_properties)
layer = build_layer_with_wizard_properties(properties)
@options = presenter_with_style_properties(layer).to_poro['options']
@fill_color = @options['style_properties']['properties']['fill']['color']
@fill_size = @options['style_properties']['properties']['fill']['size']
@stroke_color = @options['style_properties']['properties']['stroke']['color']
@stroke_size = @options['style_properties']['properties']['stroke']['size']
end
it 'sets "none" as default blending' do
@options['style_properties']['properties']['blending'].should eq 'none'
end
it 'line-width becomes fixed stroke size' do
expect(@stroke_size).to include('fixed' => line_width)
end
it 'line-color becomes fixed stroke color' do
expect(@stroke_color).to include('fixed' => line_color)
end
it 'line-opacity becomes opacity' do
expect(@stroke_color).to include('opacity' => line_opacity)
end
end
describe 'point geometry type' do
before(:each) do
properties = category_wizard_properties
properties['properties'].merge!(marker_category_properties)
layer = build_layer_with_wizard_properties(properties)
options = presenter_with_style_properties(layer).to_poro['options']
@fill_color = options['style_properties']['properties']['fill']['color']
@fill_size = options['style_properties']['properties']['fill']['size']
@stroke_color = options['style_properties']['properties']['stroke']['color']
@stroke_size = options['style_properties']['properties']['stroke']['size']
end
describe 'fill' do
it 'has fill size fixed 10' do
expect(@fill_size).to include('fixed' => 10)
end
it 'generates not fixed color but range from categories colors' do
expect(@fill_color).not_to include('fixed' => anything)
expect(@fill_color).to include('range' => [COLOR_1, COLOR_2])
end
it 'generates domain from titles' do
expect(@fill_color).to include('domain' => [title_1, title_2])
end
it 'property becomes attribute' do
expect(@fill_color).to include('attribute' => property)
expect(@fill_size).not_to include('attribute' => property)
end
it 'marker-opacity becomes opacity' do
expect(@fill_color).to include('opacity' => opacity)
end
it 'bins defaults to 10' do
expect(@fill_color).to include('bins' => 10)
end
end
describe 'stroke' do
it 'marker-line-width becomes fixed stroke size' do
expect(@stroke_size).to include('fixed' => marker_line_width)
end
it 'marker-line-color becomes fixed stroke color' do
expect(@stroke_color).to include('fixed' => marker_line_color)
end
it 'marker-line-opacity becomes opacity' do
expect(@stroke_color).to include('opacity' => marker_line_opacity)
end
end
end
describe 'line geometry type' do
before(:each) do
properties = category_wizard_properties
properties['properties'].merge!(line_category_properties)
properties['properties']['geometry_type'] = 'line'
layer = build_layer_with_wizard_properties(properties)
options = presenter_with_style_properties(layer).to_poro['options']
@stroke_color = options['style_properties']['properties']['stroke']['color']
@stroke_size = options['style_properties']['properties']['stroke']['size']
end
it 'generates fixed size from line_width' do
expect(@stroke_size).to include('fixed' => line_width)
end
it 'generates color range from categories colors' do
expect(@stroke_color).to include('range' => [COLOR_1, COLOR_2])
end
it 'property becomes attribute' do
expect(@stroke_color).to include('attribute' => property)
expect(@stroke_size).not_to include('attribute' => property)
end
it 'line-width becomes fixed stroke size' do
expect(@stroke_size).to include('fixed' => line_width)
end
it 'line-color becomes fixed stroke color' do
expect(@stroke_color).to include('fixed' => line_color)
end
it 'line-opacity becomes opacity' do
expect(@stroke_color).to include('opacity' => line_opacity)
end
it 'bins defaults to 10' do
expect(@stroke_color).to include('bins' => 10)
end
describe 'stroke' do
let(:line_width) { 6 }
let(:line_color) { "#0F3B82" }
let(:line_opacity) { 0.7 }
let(:line_comp_op) { "none" }
let(:simple_line_wizard_properties) do
{
"type" => "polygon",
"geometry_type" => "line",
"properties" =>
{
"line-width" => line_width,
"line-color" => line_color,
"line-opacity" => line_opacity,
"line-comp-op" => line_comp_op,
"geometry_type" => "line"
}
}
end
before(:each) do
layer = build_layer_with_wizard_properties(simple_line_wizard_properties)
options = presenter_with_style_properties(layer).to_poro['options']
@properties = options['style_properties']['properties']
@stroke = @properties['stroke']
@stroke_color = @stroke['color']
@stroke_size = @stroke['size']
end
it 'generates stroke' do
expect(@stroke_size).to include('fixed' => line_width)
expect(@stroke_color).to include('fixed' => line_color)
expect(@stroke_color).to include('opacity' => line_opacity)
expect(@properties).to include('blending' => line_comp_op)
end
end
end
end
shared_examples_for 'torque wizard family' do
describe 'animated' do
it 'property becomes attribute' do
expect(@animated).to include('attribute' => property)
end
it 'property becomes attribute only at animated' do
expect(@fill['color']).not_to include('attribute' => property)
end
it 'torque-duration becomes duration' do
expect(@animated).to include('duration' => torque_duration)
end
it 'torque-frame-count becomes steps' do
expect(@animated).to include('steps' => torque_frame_count)
end
it 'torque-resolution becomes resolution' do
expect(@animated).to include('resolution' => torque_resolution)
end
it 'torque-trails becomes trails' do
expect(@animated).to include('trails' => torque_trails)
end
it "doesn't include redundant animated enabled option" do
expect(@animated).not_to include('enabled')
end
end
end
shared_examples_for 'torque blend wizard family' do
describe 'torque-blend-mode' do
it 'becomes blending' do
expect(@properties).to include('blending' => torque_blend_mode)
end
end
end
shared_examples_for 'torque animated family' do
it_behaves_like 'torque wizard family'
it 'type is animated' do
expect(@style).to include('type' => 'animation')
end
it 'generates a timeseries widget' do
@layer.widgets.where(type: 'time-series').any?
end
end
describe 'torque' do
it_behaves_like 'torque animated family'
it_behaves_like 'torque blend wizard family'
let(:torque_blend_mode) { "lighter" }
let(:property) { "fecha_date" }
let(:marker_width) { 6 }
let(:torque_cumulative) { false }
let(:torque_duration) { 30 }
let(:torque_frame_count) { 256 }
let(:torque_resolution) { 2 }
let(:torque_trails) { 3 }
let(:torque_wizard_properties) do
{
"type" => "torque",
"properties" =>
{
"torque-cumulative" => torque_cumulative,
"property" => property,
"marker-type" => "ellipse",
"layer-type" => "torque",
"marker-width" => marker_width,
"marker-fill" => "#0F3B82",
"marker-opacity" => 0.9,
"marker-line-width" => 0,
"marker-line-color" => "#FFF",
"marker-line-opacity" => 1,
"torque-duration" => torque_duration,
"torque-frame-count" => torque_frame_count,
"torque-blend-mode" => torque_blend_mode,
"torque-trails" => torque_trails,
"torque-resolution" => torque_resolution,
"zoom" => 15,
"geometry_type" => "point"
}
}
end
before(:each) do
@layer = build_layer_with_wizard_properties(torque_wizard_properties)
options = presenter_with_style_properties(@layer).to_poro['options']
@style = options['style_properties']
@properties = @style['properties']
@animated = @properties['animated']
@fill = @properties['fill']
@fill_color = @fill['color']
@fill_size = @fill['size']
end
it 'torque-cumulative becomes overlap' do
expect(@animated).to include('overlap' => torque_cumulative)
end
it 'marker-width becomes fill size fixed' do
expect(@fill_size).to include('fixed' => marker_width)
end
describe 'torque-blend-mode' do
it 'turns source-over into src-over' do
source_over_torque_wizard_properties = torque_wizard_properties
source_over_torque_wizard_properties['properties']['torque-blend-mode'] = 'source-over'
layer = build_layer_with_wizard_properties(source_over_torque_wizard_properties)
options = presenter_with_style_properties(layer).to_poro['options']
options['style_properties']['properties']['blending'].should eq 'src-over'
end
end
end
end
describe 'torque cat' do
it_behaves_like 'torque animated family'
it_behaves_like 'torque blend wizard family'
let(:torque_blend_mode) { "lighter" }
let(:property) { "fecha_date" }
let(:property_cat) { "aforo" }
let(:torque_duration) { 30 }
let(:torque_frame_count) { 256 }
let(:torque_resolution) { 2 }
let(:torque_trails) { 3 }
let(:torque_cat_wizard_properties) do
{
"type" => "torque",
"properties" =>
{
"property" => property,
"marker-type" => "ellipse",
"layer-type" => "torque",
"property_cat" => property_cat,
"marker-width" => 6,
"marker-fill" => "#0F3B82",
"marker-opacity" => 0.9,
"marker-line-width" => 0,
"marker-line-color" => "#FFF",
"marker-line-opacity" => 1,
"torque-duration" => torque_duration,
"torque-frame-count" => torque_frame_count,
"torque-blend-mode" => torque_blend_mode,
"torque-trails" => torque_trails,
"torque-resolution" => torque_resolution,
"zoom" => 15,
"geometry_type" => "point",
"categories" => [
{
"title" => 100,
"title_type" => "number",
"color" => COLOR_1,
"value_type" => "color"
},
{
"title" => 200,
"title_type" => "number",
"color" => COLOR_2,
"value_type" => "color"
}
]
}
}
end
before(:each) do
@layer = build_layer_with_wizard_properties(torque_cat_wizard_properties)
options = presenter_with_style_properties(@layer).to_poro['options']
@style = options['style_properties']
@properties = @style['properties']
@animated = @properties['animated']
@fill = @properties['fill']
@fill_color = @fill['color']
@fill_size = @fill['size']
end
it 'generates color range from categories colors' do
expect(@fill_color).to include('range' => [COLOR_1, COLOR_2])
end
it 'generates color range based on attribute' do
expect(@fill_color).to include('attribute' => 'aforo')
end
end
describe 'density' do
let(:query_wrapper) { "with meta ... <%= sql %> ..." }
let(:color_ramp) { "red" }
let(:polygon_size) { 15 }
let(:density_wizard_properties) do
{
"type" => "density",
"properties" =>
{
"geometry_type" => "point",
"method" => "5 Buckets",
"color_ramp" => color_ramp,
"polygon-opacity" => 0.8,
"line-width" => 0.5,
"line-color" => "#FFF",
"line-opacity" => 1,
"polygon-size" => polygon_size,
"polygon-comp-op" => "none",
"zoom" => 15
}
}
end
before(:each) do
options = { 'query_wrapper' => query_wrapper, 'wizard_properties' => density_wizard_properties }
layer = FactoryGirl.build(:carto_layer, options: options)
@options = presenter_with_style_properties(layer).to_poro['options']
@style = @options['style_properties']
@properties = @style['properties']
@aggregation = @properties['aggregation']
@fill_color = @properties['fill']['color']
@stroke = @properties['stroke']
end
it 'sets query_wrapper at sql_wrap' do
@options['sql_wrap'].should eq query_wrapper
end
it 'maps point geometry_type to hexabins type' do
expect(@style).to include('type' => 'hexabins')
end
it 'maps Rectangles geometry_type to squares type' do
properties = density_wizard_properties
properties['properties']['geometry_type'] = 'Rectangles'
layer = build_layer_with_wizard_properties(properties)
options = presenter_with_style_properties(layer).to_poro['options']
expect(options['style_properties']).to include('type' => 'squares')
end
describe 'aggregation' do
it 'has defaults' do
expect(@aggregation).to include(
"value" => {
"operator" => 'COUNT',
"attribute" => ''
}
)
end
it 'takes size from polygon-size' do
expect(@aggregation).to include("size" => polygon_size)
end
end
describe 'fill' do
it 'transform color_ramp to color range' do
expect(@fill_color).to include('range' => color_ramp)
end
end
describe 'stroke' do
it 'takes width from line-width' do
expect(@stroke['size']).to include('fixed' => 0.5)
end
it 'takes color from line-color' do
expect(@stroke['color']).to include('fixed' => '#FFF')
end
it 'takes opacity from line-opacity' do
expect(@stroke['color']).to include('opacity' => 1)
end
end
end
describe 'heatmap' do
shared_examples_for 'heatmap' do
describe 'aggregation' do
before(:each) do
@aggregation = @style['properties']['aggregation']
end
it 'takes size from torque-resolution' do
expect(@aggregation).to include('size' => torque_resolution)
end
it 'has COUNT for value operator and empty string for attribute' do
expect(@aggregation['value']).to include('operator' => 'COUNT', 'attribute' => '')
end
end
describe 'properties' do
before(:each) do
@properties = @style['properties']
end
describe 'fill' do
it 'has size fixed 35' do
expect(@fill['size']).to include('fixed' => 35)
end
describe 'color' do
before(:each) do
@color = @fill['color']
end
it "has attribute: points_agg, default range color array, bins: 6 and opacity from marker_opacity" do
expect(@color).to include('attribute' => 'points_agg',
'range' => ['blue', 'cyan', 'lightgreen', 'yellow', 'orange', 'red'],
'bins' => 6,
'opacity' => marker_opacity)
end
end
end
end
end
let(:heatmap_wizard_properties) do
{ "type" => "torque_heat",
"properties" =>
{
"marker-width" => 35,
"layer-type" => "torque",
"marker-file" => "url(http://s3.amazonaws.com/com.cartodb.assets.static/alphamarker.png)",
"image-filters" => "colorize-alpha(blue, cyan, lightgreen, yellow , orange, red)",
"marker-opacity" => marker_opacity,
"heat-animated" => animated,
"torque-cumulative" => false,
"property" => property,
"torque-duration" => torque_duration,
"torque-frame-count" => torque_frame_count,
"torque-trails" => torque_trails,
"torque-resolution" => torque_resolution,
"zoom" => 3,
"geometry_type" => "point",
"text-placement-type" => "simple",
"text-label-position-tolerance" => 10
}
}
end
before(:each) do
@layer = build_layer_with_wizard_properties(heatmap_wizard_properties)
options = presenter_with_style_properties(@layer).to_poro['options']
@style = options['style_properties']
@properties = @style['properties']
@animated = @properties['animated']
@fill = @properties['fill']
@fill_color = @fill['color']
@fill_size = @fill['size']
end
describe 'animated' do
let(:torque_resolution) { 8 }
let(:marker_opacity) { 0.4 }
let(:torque_trails) { 2 }
let(:torque_frame_count) { 32 }
let(:torque_duration) { 10 }
let(:property) { "actor_post" }
let(:animated) { true }
it_behaves_like 'torque animated family'
it_behaves_like 'heatmap'
end
describe 'without animation' do
let(:torque_resolution) { 8 }
let(:marker_opacity) { 0.4 }
let(:torque_trails) { 2 }
let(:torque_frame_count) { 1 }
let(:torque_duration) { 10 }
let(:property) { "cartodb_id" }
let(:animated) { false }
it 'is generated from torque_heat' do
expect(@style).to include('type' => 'heatmap')
end
it_behaves_like 'torque wizard family'
it_behaves_like 'heatmap'
end
end
describe 'labels' do
describe 'without text-* properties' do
let(:no_text_wizard_properties) do
{
"type" => "choropleth",
"properties" => { "property" => 'actor_foll' }
}
end
it 'generates disabled labels' do
layer = build_layer_with_wizard_properties(no_text_wizard_properties)
options = presenter_with_style_properties(layer).to_poro['options']
options['style_properties']['properties']['labels']['enabled'].should be_false
end
end
describe 'with text-name `None`' do
let(:none_text_name_wizard_properties) do
{
"type" => "choropleth",
"properties" =>
{
"text-name" => 'None',
"text-face-name" => 'something'
}
}
end
it 'generates disabled labels' do
layer = build_layer_with_wizard_properties(none_text_name_wizard_properties)
options = presenter_with_style_properties(layer).to_poro['options']
options['style_properties']['properties']['labels']['enabled'].should be_false
end
end
describe 'with text-* properties' do
let(:text_name) { "Something" }
let(:text_face_name) { "DejaVu Sans Book" }
let(:text_size) { 10 }
let(:text_fill) { "#000" }
let(:text_halo_radius) { 1 }
let(:text_halo_fill) { "#ABC" }
let(:text_dy) { -10 }
let(:text_allow_overlap) { true }
let(:text_placement_type) { "simple" }
let(:text_wizard_properties) do
{
"type" => "choropleth",
"properties" =>
{
"text-name" => text_name,
"text-face-name" => text_face_name,
"text-size" => text_size,
"text-fill" => text_fill,
"text-halo-fill" => text_halo_fill,
"text-halo-radius" => text_halo_radius,
"text-dy" => text_dy,
"text-allow-overlap" => text_allow_overlap,
"text-placement-type" => text_placement_type,
"text-label-position-tolerance" => 10,
"text-placement" => "point"
}
}
end
before(:each) do
layer = build_layer_with_wizard_properties(text_wizard_properties)
options = presenter_with_style_properties(layer).to_poro['options']
@labels = options['style_properties']['properties']['labels']
end
it 'generates labels' do
@labels.should_not be_nil
@labels['enabled'].should be_true
end
it 'text-name generates attribute' do
expect(@labels).to include('attribute' => text_name)
end
it 'text-name `None` generates `nil` attribute' do
properties = text_wizard_properties
properties['properties']['text-name'] = 'None'
layer = build_layer_with_wizard_properties(properties)
options = presenter_with_style_properties(layer).to_poro['options']
labels = options['style_properties']['properties']['labels']
expect(labels).to include('attribute' => nil)
end
it 'text-face-name generates font' do
expect(@labels).to include('font' => text_face_name)
end
it 'text-dy generates offset' do
expect(@labels).to include('offset' => text_dy)
end
it 'text-allow-overlap generates overlap' do
expect(@labels).to include('overlap' => text_allow_overlap)
end
it 'text-placement-type generates placement' do
expect(@labels).to include('placement' => text_placement_type)
end
describe 'fill' do
before(:each) do
@labels_fill = @labels['fill']
@labels_fill.should_not be_nil
@labels_fill_size = @labels_fill['size']
@labels_fill_color = @labels_fill['color']
end
it 'text-size generates fill size fixed' do
expect(@labels_fill_size).to include('fixed' => text_size)
end
it 'text-fill generates fill color fixed and opacity 1 if not present' do
expect(@labels_fill_color).to include('fixed' => text_fill, 'opacity' => 1)
end
it 'text-fill generates fill color fixed and opacity if present' do
text_with_opacity = text_wizard_properties
text_with_opacity["properties"]["text-opacity"] = OPACITY
layer = build_layer_with_wizard_properties(text_with_opacity)
options = presenter_with_style_properties(layer).to_poro['options']
labels_fill_color = options['style_properties']['properties']['labels']['fill']['color']
expect(labels_fill_color).to include('fixed' => text_fill, 'opacity' => OPACITY)
end
end
describe 'halo' do
before(:each) do
@labels_halo = @labels['halo']
@labels_halo.should_not be_nil
@labels_halo_size = @labels_halo['size']
@labels_halo_color = @labels_halo['color']
end
it 'text-halo-radius generates halo size fixed' do
expect(@labels_halo_size).to include('fixed' => text_halo_radius)
end
it 'text-halo-fill generates halo color fixed and opacity 1 if not present' do
expect(@labels_halo_color).to include('fixed' => text_halo_fill, 'opacity' => 1)
end
it 'text-halo-fill generates fill color fixed and opacity if present' do
halo_with_opacity = text_wizard_properties
halo_with_opacity["properties"]["text-halo-opacity"] = OPACITY
layer = build_layer_with_wizard_properties(halo_with_opacity)
options = presenter_with_style_properties(layer).to_poro['options']
labels_halo_color = options['style_properties']['properties']['labels']['halo']['color']
expect(labels_halo_color).to include('fixed' => text_halo_fill, 'opacity' => OPACITY)
end
end
end
end
end
end