require 'spec_helper' describe JsRoutes, "options" do let(:generated_js) do JsRoutes.generate( module_type: nil, namespace: 'Routes', **_options ) end before(:each) do evaljs(_presetup) if _presetup with_warnings(_warnings) do evaljs(generated_js) App.routes.default_url_options = _options[:default_url_options] || {} end end after(:each) do App.routes.default_url_options = {} end let(:_presetup) { nil } let(:_options) { {} } let(:_warnings) { true } describe "serializer" do context "when specified" do # define custom serializer # this is a nonsense serializer, which always returns foo=bar # for all inputs let(:_presetup){ %q(function myCustomSerializer(object, prefix) { return "foo=bar"; }) } let(:_options) { {:serializer => "myCustomSerializer"} } it "should set configurable serializer" do # expect the nonsense serializer above to have appened foo=bar # to the end of the path expectjs(%q(Routes.inboxes_path())).to eql("/inboxes?foo=bar") end end context "when specified, but not function" do let(:_presetup){ %q(var myCustomSerializer = 1) } let(:_options) { {:serializer => "myCustomSerializer"} } it "should throw error" do expect { evaljs(%q(Routes.inboxes_path({a: 1}))) }.to raise_error(js_error_class) end end context "when configured in js" do let(:_options) { {:serializer =>%q(function (object, prefix) { return "foo=bar"; })} } it "uses JS serializer" do evaljs("Routes.configure({serializer: function (object, prefix) { return 'bar=baz'; }})") expectjs(%q(Routes.inboxes_path({a: 1}))).to eql("/inboxes?bar=baz") end end end context "when exclude is specified" do let(:_options) { {:exclude => /^admin_/} } it "should exclude specified routes from file" do expectjs("Routes.admin_users_path").to be_nil end it "should not exclude routes not under specified pattern" do expectjs("Routes.inboxes_path()").not_to be_nil end context "for rails engine" do let(:_options) { {:exclude => /^blog_app_posts/} } it "should exclude specified engine route" do expectjs("Routes.blog_app_posts_path").to be_nil end end end context "when include is specified" do let(:_options) { {:include => /^admin_/} } it "should exclude specified routes from file" do expectjs("Routes.admin_users_path()").not_to be_nil end it "should not exclude routes not under specified pattern" do expectjs("Routes.inboxes_path").to be_nil end context "with camel_case option" do let(:_options) { {include: /^admin_/, camel_case: true} } it "should exclude specified routes from file" do expectjs("Routes.adminUsersPath()").not_to be_nil end it "should not exclude routes not under specified pattern" do expectjs("Routes.inboxesPath").to be_nil end end context "for rails engine" do let(:_options) { {:include => /^blog_app_posts/} } it "should include specified engine route" do expectjs("Routes.blog_app_posts_path()").not_to be_nil end end end context "when prefix with trailing slash is specified" do let(:_options) { {:prefix => "/myprefix/" } } it "should render routing with prefix" do expectjs("Routes.inbox_path(1)").to eq("/myprefix#{test_routes.inbox_path(1)}") end it "should render routing with prefix set in JavaScript" do evaljs("Routes.configure({prefix: '/newprefix/'})") expectjs("Routes.config().prefix").to eq("/newprefix/") expectjs("Routes.inbox_path(1)").to eq("/newprefix#{test_routes.inbox_path(1)}") end end context "when prefix with http:// is specified" do let(:_options) { {:prefix => "http://localhost:3000" } } it "should render routing with prefix" do expectjs("Routes.inbox_path(1)").to eq(_options[:prefix] + test_routes.inbox_path(1)) end end context "when prefix without trailing slash is specified" do let(:_options) { {:prefix => "/myprefix" } } it "should render routing with prefix" do expectjs("Routes.inbox_path(1)").to eq("/myprefix#{test_routes.inbox_path(1)}") end it "should render routing with prefix set in JavaScript" do evaljs("Routes.configure({prefix: '/newprefix/'})") expectjs("Routes.inbox_path(1)").to eq("/newprefix#{test_routes.inbox_path(1)}") end end context "when default format is specified" do let(:_options) { {:default_url_options => {format: "json"}} } let(:_warnings) { nil } if Rails.version >= "5" it "should render routing with default_format" do expectjs("Routes.inbox_path(1)").to eq(test_routes.inbox_path(1)) end it "should render routing with default_format and zero object" do expectjs("Routes.inbox_path(0)").to eq(test_routes.inbox_path(0)) end end it "should override default_format when spefified implicitly" do expectjs("Routes.inbox_path(1, {format: 'xml'})").to eq(test_routes.inbox_path(1, :format => "xml")) end it "should override nullify implicitly when specified implicitly" do expectjs("Routes.inbox_path(1, {format: null})").to eq(test_routes.inbox_path(1, format: nil)) end it "shouldn't require the format" do expectjs("Routes.json_only_path()").to eq(test_routes.json_only_path) end end it "shouldn't include the format when {:format => false} is specified" do expectjs("Routes.no_format_path()").to eq(test_routes.no_format_path()) expectjs("Routes.no_format_path({format: 'json'})").to eq(test_routes.no_format_path(format: 'json')) end describe "default_url_options" do context "with optional route parts" do context "provided by the default_url_options" do let(:_options) { { :default_url_options => { :optional_id => "12", :format => "json" } } } it "should use this options to fill optional parameters" do expectjs("Routes.things_path()").to eq(test_routes.things_path(12)) end end context "provided inline by the method parameters" do let(:options) { { :default_url_options => { :optional_id => "12" } } } it "should overwrite the default_url_options" do expectjs("Routes.things_path({ optional_id: 34 })").to eq(test_routes.things_path(optional_id: 34)) end end context "not provided" do let(:_options) { { :default_url_options => { :format => "json" } } } it "breaks" do expectjs("Routes.foo_all_path()").to eq(test_routes.foo_all_path) end end end context "with required route parts" do let(:_options) { { :default_url_options => { :inbox_id => "12" } } } it "should use this options to fill optional parameters" do expectjs("Routes.inbox_messages_path()").to eq(test_routes.inbox_messages_path) end end context "with optional and required route parts" do let(:_options) { {:default_url_options => { :optional_id => "12" } } } it "should use this options to fill the optional parameters" do expectjs("Routes.thing_path(1)").to eq test_routes.thing_path(1, { optional_id: "12" }) end context "when passing options that do not have defaults" do it "should use this options to fill the optional parameters" do expectjs("Routes.thing_path(1, { format: 'json' })").to eq test_routes.thing_path(1, { optional_id: "12", format: "json" } ) # test_routes.thing_path needs optional_id here to generate the correct route. Not sure why. end end end context "when overwritten on JS level" do let(:_options) { { :default_url_options => { :format => "json" } } } it "uses JS defined value" do evaljs("Routes.configure({default_url_options: {format: 'xml'}})") expectjs("Routes.inboxes_path()").to eq(test_routes.inboxes_path(format: 'xml')) end end end describe "trailing_slash" do context "with default option" do let(:_options) { Hash.new } it "should working in params" do expectjs("Routes.inbox_path(1, {trailing_slash: true})").to eq(test_routes.inbox_path(1, :trailing_slash => true)) end it "should working with additional params" do expectjs("Routes.inbox_path(1, {trailing_slash: true, test: 'params'})").to eq(test_routes.inbox_path(1, :trailing_slash => true, :test => 'params')) end end context "with default_url_options option" do let(:_options) { {:default_url_options => {:trailing_slash => true}} } it "should working" do expectjs("Routes.inbox_path(1, {test: 'params'})").to eq(test_routes.inbox_path(1, :trailing_slash => true, :test => 'params')) end it "should remove it by params" do expectjs("Routes.inbox_path(1, {trailing_slash: false})").to eq(test_routes.inbox_path(1, trailing_slash: false)) end end context "with disabled default_url_options option" do let(:_options) { {:default_url_options => {:trailing_slash => false}} } it "should not use trailing_slash" do expectjs("Routes.inbox_path(1, {test: 'params'})").to eq(test_routes.inbox_path(1, :test => 'params')) end it "should use it by params" do expectjs("Routes.inbox_path(1, {trailing_slash: true})").to eq(test_routes.inbox_path(1, :trailing_slash => true)) end end end describe "camel_case" do context "with default option" do let(:_options) { Hash.new } it "should use snake case routes" do expectjs("Routes.inbox_path(1)").to eq(test_routes.inbox_path(1)) expectjs("Routes.inboxPath").to be_nil end end context "with true" do let(:_options) { { :camel_case => true } } it "should generate camel case routes" do expectjs("Routes.inbox_path").to be_nil expectjs("Routes.inboxPath").not_to be_nil expectjs("Routes.inboxPath(1)").to eq(test_routes.inbox_path(1)) expectjs("Routes.inboxMessagesPath(10)").to eq(test_routes.inbox_messages_path(:inbox_id => 10)) end end end describe "url_links" do context "with default option" do let(:_options) { Hash.new } it "should generate only path links" do expectjs("Routes.inbox_path(1)").to eq(test_routes.inbox_path(1)) expectjs("Routes.inbox_url").to be_nil end end context "when configuring with default_url_options" do context "when only host option is specified" do let(:_options) { { :url_links => true, :default_url_options => {:host => "example.com"} } } it "uses the specified host, defaults protocol to http, defaults port to 80 (leaving it blank)" do expectjs("Routes.inbox_url(1)").to eq("http://example.com#{test_routes.inbox_path(1)}") end it "does not override protocol when specified in route" do expectjs("Routes.new_session_url()").to eq("https://example.com#{test_routes.new_session_path}") end it "does not override host when specified in route" do expectjs("Routes.sso_url()").to eq(test_routes.sso_url) end it "does not override port when specified in route" do expectjs("Routes.portals_url()").to eq("http://example.com:8080#{test_routes.portals_path}") end end context "when default host and protocol are specified" do let(:_options) { { :url_links => true, :default_url_options => {:host => "example.com", :protocol => "ftp"} } } it "uses the specified protocol and host, defaults port to 80 (leaving it blank)" do expectjs("Routes.inbox_url(1)").to eq("ftp://example.com#{test_routes.inbox_path(1)}") end it "does not override protocol when specified in route" do expectjs("Routes.new_session_url()").to eq("https://example.com#{test_routes.new_session_path}") end it "does not override host when host is specified in route" do expectjs("Routes.sso_url()").to eq("ftp://sso.example.com#{test_routes.sso_path}") end it "does not override port when specified in route" do expectjs("Routes.portals_url()").to eq("ftp://example.com:8080#{test_routes.portals_path}") end end context "when default host and port are specified" do let(:_options) { { :url_links => true, :default_url_options => {:host => "example.com", :port => 3000} } } it "uses the specified host and port, defaults protocol to http" do expectjs("Routes.inbox_url(1)").to eq("http://example.com:3000#{test_routes.inbox_path(1)}") end it "does not override protocol when specified in route" do expectjs("Routes.new_session_url()").to eq("https://example.com:3000#{test_routes.new_session_path}") end it "does not override host, protocol, or port when host is specified in route" do expectjs("Routes.sso_url()").to eq("http://sso.example.com:3000" + test_routes.sso_path) end it "does not override parts when specified in route" do expectjs("Routes.secret_root_url()").to eq(test_routes.secret_root_url) end end context "with camel_case option" do let(:_options) { { :camel_case => true, :url_links => true, :default_url_options => {:host => "example.com"} } } it "should generate path and url links" do expectjs("Routes.inboxUrl(1)").to eq("http://example.com#{test_routes.inbox_path(1)}") end end context "with prefix option" do let(:_options) { { :prefix => "/api", :url_links => true, :default_url_options => {:host => 'example.com'} } } it "should generate path and url links" do expectjs("Routes.inbox_url(1)").to eq("http://example.com/api#{test_routes.inbox_path(1)}") end end context "with compact option" do let(:_options) { { :compact => true, :url_links => true, :default_url_options => {:host => 'example.com'} } } it "does not affect url helpers" do expectjs("Routes.inbox_url(1)").to eq("http://example.com#{test_routes.inbox_path(1)}") end end end context 'when window.location is present' do let(:current_protocol) { 'http:' } # window.location.protocol includes the colon character let(:current_hostname) { 'current.example.com' } let(:current_port){ '' } # an empty string means port 80 let(:current_host) do host = "#{current_hostname}" host += ":#{current_port}" unless current_port == '' host end let(:_presetup) do location = { protocol: current_protocol, hostname: current_hostname, port: current_port, host: current_host, } [ "const window = this;", "window.location = #{ActiveSupport::JSON.encode(location)};", ].join("\n") end context "without specifying a default host" do let(:_options) { { :url_links => true } } it "uses the current host" do expectjs("Routes.inbox_path").not_to be_nil expectjs("Routes.inbox_url").not_to be_nil expectjs("Routes.inbox_url(1)").to eq("http://current.example.com#{test_routes.inbox_path(1)}") expectjs("Routes.inbox_url(1, { test_key: \"test_val\" })").to eq("http://current.example.com#{test_routes.inbox_path(1, :test_key => "test_val")}") expectjs("Routes.new_session_url()").to eq("https://current.example.com#{test_routes.new_session_path}") end it "doesn't use current when specified in the route" do expectjs("Routes.sso_url()").to eq(test_routes.sso_url) end it "uses host option as an argument" do expectjs("Routes.secret_root_url({host: 'another.com'})").to eq(test_routes.secret_root_url(host: 'another.com')) end it "uses port option as an argument" do expectjs("Routes.secret_root_url({host: 'localhost', port: 8080})").to eq(test_routes.secret_root_url(host: 'localhost', port: 8080)) end it "uses protocol option as an argument" do expectjs("Routes.secret_root_url({host: 'localhost', protocol: 'https'})").to eq(test_routes.secret_root_url(protocol: 'https', host: 'localhost')) end it "uses subdomain option as an argument" do expectjs("Routes.secret_root_url({subdomain: 'custom'})").to eq(test_routes.secret_root_url(subdomain: 'custom')) end end end context 'when window.location is not present' do context 'without specifying a default host' do let(:_options) { { url_links: true } } it 'generates path' do expectjs("Routes.inbox_url(1)").to eq test_routes.inbox_path(1) expectjs("Routes.new_session_url()").to eq test_routes.new_session_path end end end end describe "when the compact mode is enabled" do let(:_options) { { :compact => true } } it "removes _path suffix from path helpers" do expectjs("Routes.inbox_path").to be_nil expectjs("Routes.inboxes()").to eq(test_routes.inboxes_path()) expectjs("Routes.inbox(2)").to eq(test_routes.inbox_path(2)) end context "with url_links option" do around(:each) do |example| ActiveSupport::Deprecation.silence do example.run end end let(:_options) { { :compact => true, :url_links => true, default_url_options: {host: 'localhost'} } } it "should not strip urls" do expectjs("Routes.inbox(1)").to eq(test_routes.inbox_path(1)) expectjs("Routes.inbox_url(1)").to eq("http://localhost#{test_routes.inbox_path(1)}") end end end describe "special_options_key" do let(:_options) { { special_options_key: :__options__ } } it "can be redefined" do expect { expectjs("Routes.inbox_message_path({inbox_id: 1, id: 2, _options: true})").to eq("") }.to raise_error(js_error_class) expectjs("Routes.inbox_message_path({inbox_id: 1, id: 2, __options__: true})").to eq(test_routes.inbox_message_path(inbox_id: 1, id: 2)) end end describe "when application is specified" do let(:_options) { {:application => BlogEngine::Engine} } it "should include specified engine route" do expectjs("Routes.posts_path()").not_to be_nil end end describe "documentation option" do let(:_options) { {documentation: false} } it "disables documentation generation" do expect(generated_js).not_to include("@param") expect(generated_js).not_to include("@returns") end end end