Giter Site home page Giter Site logo

crismali / magic_lamp Goto Github PK

View Code? Open in Web Editor NEW
67.0 5.0 7.0 502 KB

Gets your Rails templates/json into your JavaScript specs.

License: Apache License 2.0

Ruby 54.31% JavaScript 40.66% CSS 0.90% HTML 4.13%
rails javascript fixtures javascript-specs ruby

magic_lamp's Introduction

Magic Lamp

Gem Version Build Status

Magic Lamp helps you get your Rails templates into your JavaScript tests. This means that way your JavaScript tests break if you change your templates and you don't have to create so many fixtures. Plus, it lets you test your views in JavaScript. All you have to do is set up your data just like you would in a controller.

Table of Contents

  1. Installation
  2. Basic Usage
  3. Where the files go
  4. Tasks
  5. Ruby API
  6. JavaScript API
  7. Errors
  8. Sweet Aliases
  9. Contributing

Installation

Add this line to your application's Gemfile:

  gem "magic_lamp"

And then execute:

$ bundle install

Then paste mount MagicLamp::Genie, at: "/magic_lamp" if defined?(MagicLamp) into your config/routes.rb like so:

Rails.application.routes.draw do
  # ...
  mount MagicLamp::Genie, at: "/magic_lamp" if defined?(MagicLamp)
  # ...
end

This mounts the Magic Lamp engine in your app.

Then drop this:

//= require magic_lamp

at the top of your spec_helper.js (assuming you're using JavaScript spec runner for Rails that allows the use of Sprockets directives).

If your JavaScript test runner doesn't support XHR requests, you can drop this in instead:

//= require magic_lamp
//= require magic_lamp/all_fixtures

//= require magic_lamp/all_fixtures will load all of your fixtures without making any XHR requests.

Note: when loading your fixtures via Sprockets directives you will likely want to disable Sprockets caching in whatever environment your JavaScript tests are running. You can do so by putting the following in the appropriate environment config file:

config.assets.configure do |env|
  env.cache = ActiveSupport::Cache.lookup_store(:null_store)
end

Now you've got the basic setup.

Debugging

Visit /magic_lamp/lint in your browser to lint your fixtures. You can also run rake magic_lamp:lint (or rake mll for short) to lint your fixtures from the command line.

Loading Helpers

Simply load your helpers in the magic_lamp_config.rb file like so:

# in magic_lamp_config.rb
Dir[Rails.root.join("spec", "support", "magic_lamp_helpers/**/*.rb")].each { |f| load f }

Supported test runners

Magic Lamp has been shown to work with:

It will likely work with any test runner that supports XHR requests or Sprockets directives.

With Database Cleaner

You don't need Database Cleaner to use this gem, but this is probably the setup most people want.

First make sure you have Database Cleaner installed, then you'll want to do something like this:

require "database_cleaner"

MagicLamp.configure do |config|

  DatabaseCleaner.strategy = :transaction

  config.before_each do
    DatabaseCleaner.start
  end

  config.after_each do
    DatabaseCleaner.clean
  end
end

in a file called magic_lamp_config.rb which you can place anywhere in your spec or test directories.

This way you can take advantage of after_create callbacks for your fixture setup without polluting your database every time you run your JavaScript specs.

With FactoryGirl

If you're using FactoryGirl, Magic Lamp will call FactoryGirl.reload for you to save you some autoloader pain.

Basic Usage

Magic Lamp will load all files in your spec or test directory that end with _lamp.rb (your app's "lamp files). I'd recommend starting with a single magic_lamp.rb file and breaking it into smaller files once it gets unwieldy (one for each controller would be a good approach).

In your lamp files you just call MagicLamp.fixture like so:

MagicLamp.fixture do
  @order = Order.new
  render partial: "orders/form"
end

Inside the block you pass to fixture you're in the scope of a controller so you can set up any instance variables your templates depend on. In this case we're using the default controller which is your ApplicationController. We're also using the default name for the fixture which is whatever render receives to identify the template (ie the symbol or string argument to render or whatever is at the :template or :partial key in the argument hash).

render here also works normally except that it won't render the layout by default.

Then in your JavaScript you can call load:

beforeEach(function() {
  MagicLamp.load("orders/form");
});

which will put the orders/form partial in a div with a class of magic-lamp (this all happens synchronously). Then you can go nuts testing your JavaScript against your actual template. If you'd like to only make one request for your templates, simply call MagicLamp.preload(); in your spec_helper.js to populate Magic Lamp's cache.

Loading multiple templates

Just pass more fixture names to MagicLamp.load and it will load them all. For example:

  beforeEach(function() {
    MagicLamp.load("orders/sidebar", "orders/form");
  });

with a sidebar template/partial that looks like this:

  <div class="sidebar content">Links!</div>

and a form template/partial that looks like this:

  <div class="form content">Inputs!</div>

will yield:

  <div class="magic-lamp">
    <div class="sidebar content">Links!</div>
    <div class="form content">Inputs!</div>
  </div>

Loading JSON fixtures and arbitrary strings

If you pass a block to fixture that does not invoke render, Magic Lamp will assume that you want the to_json representation of the return value of the block as your fixture (Magic Lamp will call this for you). If the return value is already a string, then Magic Lamp will return that string as is. In your JavaScript MagicLamp.loadJSON will return the JSON.parsed string while MagicLamp.loadRaw will return the string as is (you can also use loadRaw get the string version of a template rendered with render without Magic Lamp appending it to the DOM. loadJSON also won't interact with the DOM).

When sending down JSON or arbitrary strings, you must provide the fixture with a name since inferring one is impossible.

It's also good to remember that in the fixture block that even though the controller isn't rendering anything for us, the block is still scoped to the given controller which gives us access to any controller methods we might want to use to massage our data structures.

For example:

MagicLamp.define(controller: OrdersController) do
  fixture(name: "some_json") do
    OrderSerializer.new(Order.new(price: 55))
  end

  fixture(name: "some_arbitrary_string") do
    some_method_on_the_controller_that_returns_a_string("Just some string")
  end
end

Then in your JavaScript:

beforeEach(function() {
  var jsonObject = MagicLamp.loadJSON("orders/some_json");
  var someString = MagicLamp.loadRaw("orders/some_arbitrary_string");
});

A few more examples

Here we're specifying which controller should render the template via the arguments hash to fixture. This gives us access to helper methods in the fixture block and in the template. It also means we don't need a fully qualified path to the rendered template or partial.

Since we didn't specify the name of our fixture and we're not using the ApplicationController to render the template the fixture will be named "orders/order".

We're also taking advantage of render's :collection option.

MagicLamp.fixture(controller: OrdersController) do
  orders = 3.times.map { Order.new }
  render partial: "order", collection: orders
end

Here we're specifying a name with the :name option that's passed to fixture. This way we can load the fixture in our JavaScript with MagicLamp.load("custom/name") instead of the default MagicLamp.load("orders/foo"). Custom names for fixtures must be url safe strings. We're also extending the controller and its view with the AuthStub module to stub some methods that we don't want executing in our fixtures.

MagicLamp.fixture(name: "custom/name", extend: AuthStub) do
  render "orders/foo"
end

Here we're specifying both a controller and custom name. We're also setting the params[:foo] mostly to demonstrate that we have access to all of the usual controller methods.

MagicLamp.fixture(controller: OrdersController, name: "other_custom_name") do
  params[:foo] = "test"
  render :foo
end

Drying up your fixtures

If you have several fixtures that depend on the same setup (same controller, extensions, etc), you can use the define method to dry things up:

MagicLamp.define(controller: OrdersController, extend: AuthStub) do
  fixture do # orders/new
    @order = Order.new
    render :new
  end

  fixture(name: "customized_new") do # orders/customized_new
    session[:custom_user_info] = "likes movies"
    @order = Order.new
    render :new
  end

  fixture do # orders/form
    @order = Order.new
    render partial: "form"
  end

  define(namespace: "errors", extend: SomeErrorHelpers) do
    fixture(name: "form_without_price") do # orders/errors/form_without_price
      @order = Order.new
      @order.errors.add(:price, "can't be blank")
      render partial: "form"
    end

    fixture do # orders/errors/form
      @order = Order.new
      @order.errors.add(:address, "can't be blank")
      render partial: "form"
    end
  end
end

Where the files go

Config File

Magic Lamp first loads the magic_lamp_config.rb file. It can be anywhere in your spec or test directory but it's not required.

Lamp files

Magic Lamp will load any files in your spec or test directory that end with _lamp.rb.

Tasks

fixture_names

Call rake magic_lamp:fixture_names (or rake mlfn) to see a list of all of your app's fixture names.

lint

Call rake magic_lamp:lint (or rake mll) to see if there are any errors when registering or rendering your fixtures.

Ruby API

fixture

(also aliased to register_fixture and register)

It requires a block that is invoked in the context of a controller. If render is called, it renders the specified template or partial the way the controller normally would minus the layout. If you'd like a particular layout to be rendered simply specify it when you call render:

render :index, layout: "admin"

Note: Rendering the layout could be useful under some circumstances, but it is important to be aware that things will get weird if you use MagicLamp to load and entire HTML document. Especially if it contains script tags to your JavaScript.

If render is not called in the block then MagicLamp will render the to_json representation of the return value of the block unless the return value is already a string. In that case, the string is rendered as is.

It also takes an optional hash of arguments. The arguments hash recognizes:

  • :controller
    • specifies any controller class that you'd like to have render the template or partial or have the block scoped to.
    • if specified it removes the need to pass fully qualified paths to templates to render
    • the controller's name becomes the default namespace, ie OrdersController provides a default namespace of orders resulting in a template named orders/foo
  • :name
    • whatever you'd like name the fixture.
    • Specifying this option also prevents the block from being executed twice which could be a performance win. See configure for more.
    • this is required when you want to send down JSON or arbitrary strings.
  • :extend
    • takes a module or an array of modules
    • extends the controller and view context (via Ruby's extend) Also note that only symbol keys are recognized.

fixture will also execute any callbacks you've specified. See configure for more.

Example:

MagicLamp.fixture(name: "foo", controller: OrdersController) do
  @order = Order.new
  render partial: "form"
end

define

Allows you scope groups of fixtures with defaults and can be nested arbitrarily. It takes an optional hash and a required block. The hash accepts the following options:

  • :controller
    • specifies any controller class that you'd like to have render the template or partial.
    • if specified it removes the need to pass fully qualified paths to templates to render
    • the controller's name becomes the default namespace if no namespace is provided, ie OrdersController provides a default namespace of orders resulting in a template named orders/foo
  • :name
    • whatever you'd like name the fixture.
    • Specifying this option also prevents the block from being executed twice which could be a performance win. See configure for more.
  • :extend
    • takes a module or an array of modules
    • extends the controller and view context (via Ruby's extend)
  • :namespace
    • namespaces all fixtures defined within it
    • overrides the default controller namespace if passed Also note that only symbol keys are recognized.

Inside of the block you can nest more calls to define and create fixtures via the fixture method or one of its aliases.

Example:

module DefinesFoo
  def foo
    "foo!"
  end
end

module AlsoDefinesFoo
  def foo
    "also foo!"
  end
end

MagicLamp.define(controller: OrdersController, extend: DefinesFoo) do

  fixture do # orders/edit
    foo #=> "foo!"
    @order = Order.create!
    render :edit
  end

  fixture do # orders/new
    foo #=> "foo!"
    @order = Order.new
    render :new
  end

  define(namespace: "errors", extend: AlsoDefinesFoo) do

    fixture do # orders/errors/edit
      foo #=> "also foo!"
      @order = Order.create!
      @order.errors.add(:price, "Can't be negative")
      render :edit
    end

    fixture(extend: DefinesFoo) do # orders/errors/new
      foo #=> "foo!"
      @order = Order.new
      @order.errors.add(:price, "Can't be negative")
      render :new
    end
  end
end

configure

It requires a block to which it yields the configuration object. Here you can set:

  • before_each
    • takes a block
    • defaults to nil
    • called before each block you pass to fixture is executed
    • note: if you call it a second time with a second block, only the second block will be executed
  • after_each
    • takes a block
    • defaults to nil
    • called after each block you pass to fixture is executed
    • note: if you call it a second time with a second block, only the second block will be executed
  • global_defaults
    • can be set to a hash of default options that every fixture generated will inherit from. Options passed to define and fixture take precedence.
    • accepts all of the keys define accepts
  • infer_names
    • defaults to true
    • if set to true, Magic Lamp will try to infer the name of the fixture when not provided with a name parameter.
    • if set to false, the name parameter becomes required for MagicLamp.fixture (this can be done to improve performance or force your team to be more explicit)

Example:

# spec/support/magic_lamp/helpers/auth_stub.rb
module AuthStub
  def current_user
    @current_user ||= User.create!(
      email: "[email protected]",
      password: "password"
    )
  end
end

# spec/magic_lamp_config.rb (can be anywhere in /spec)
MagicLamp.configure do |config|

  Dir[Rails.root.join("spec", "support", "magic_lamp_helpers/**/*.rb")].each { |f| load f }

  # if you want to require the name parameter for the `fixture` method
  config.infer_names = false

  config.global_defaults = { extend: AuthStub }

  config.before_each do
    puts "I appear before the block passed to `fixture` executes!"
  end

  config.after_each do
    puts "I appear after the block passed to `fixture` executes!"
  end
end

JavaScript API

clean

Calling MagicLamp.clean() will remove the Magic Lamp fixture container from the page.

If you don't want any dom elements from a fixture hanging around between specs, throw it in a global afterEach block. Calling it with nothing to clean won't result in an error.

Example:

  afterEach(function() {
    MagicLamp.clean();
  });

load

Call MagicLamp.load to load a fixture. It requires the name of the fixture and which will be loaded into a div with a class of magic-lamp. It will destroy the previous fixture container if present so you never end up with duplicate fixture containers or end up with dom elements from previous loads. It will hit the network only on the first request for a given fixture. If you never want load to hit the network, call MagicLamp.preload() or use //= require magic_lamp/all_fixtures before your specs.

You can load multiple fixtures into the dom at the same time by simply passing more arguments to load.

The call to get your template is completely synchronous.

Example:

  beforeEach(function() {
    MagicLamp.load("orders/foo");
  });

  // or if you wanted multiple fixtures...

  beforeEach(function() {
    MagicLamp.load("orders/foo", "orders/bar", "orders/foo", "orders/baz");
  });

loadJSON

Returns the JSON.parsed version of the fixture. It's a convenience method for JSON.parse(MagicLamp.loadRaw('some_json_fixture'));. Look here for more.

loadRaw

Returns the template, partial, JSON, or string as a raw string. Look here for more.

preload

Call MagicLamp.preload to load all of your templates into MagicLamp's cache. This means you'll only hit the network once, so the rest of your specs will be quicker and you can go wild stubbing the network.

The call to get your templates is completely synchronous.

Note: this is completely unnecessary if you use //= require magic_lamp/all_fixtures

Example:

// Probably should be in your `spec_helper.js`
MagicLamp.preload();

fixtureNames

MagicLamp.fixtureNames() will return an array of all of the fixture names available in the cache (which is all of them if you've called preload). It will also console.log them out.

Example

MagicLamp.preload();
MagicLamp.fixtureNames(); // => ['orders/foo', 'orders/bar', 'orders/baz']
// logs 'orders/foo'
// logs 'orders/bar'
// logs 'orders/baz'

globalize

MagicLamp.globalize() will put MagicLamp.clean and MagicLamp.load onto window for convenience.

Example:

MagicLamp.globalize();

describe("Foo", function() {
  beforeEach(function() {
    load("orders/foo");
  });

  afterEach(function() {
    clean();
  });

  // ...
});

Errors

If there are errors rendering any of your templates, Magic Lamp will often throw a JavaScript error. Errors will also appear in your server log (if you're running the in-browser specs).

To see errors outside of the server log (which may be noisy), you can run rake magic_lamp:lint (or rake mll) or visit /magic_lamp/lint in your browser and display any errors in your fixtures.

You can debug into your fixture generation code or even the templates themselves just as you normally would in any other part of your Rails app. If you start seeing a bunch of RenderCatcher objects instead of the code you expected, just continue through and wait for the debugger to catch again and things go back to normal. If you want to skip continuing through, simply provide an explicit name for the fixture.

If you get an ActionView::MissingTemplate error, try specifying the controller. This error is caused by a template that renders a partial without using the fully qualified path to the partial. Specifying the controller should help Rails find the template.

When rails is inferring routes for form_for, link_to, and a few other methods you'll sometimes need to change request.env["action_dispatch.request.path_parameters"] by setting action and controller. When the route is nested with with a parameter in the url like /orders/:order_id/foos/new you'll need to add the :order_id to it like so:

fixture do
  request.env["action_dispatch.request.path_parameters"] = {
    action: "new",
    controller: "foos",
    order_id: 3
  }
  render :new
end

Sweet aliases

Ruby

MagicLamp.register_fixture => fixture
MagicLamp.register => fixture
MagicLamp.rub => fixture
MagicLamp.wish => fixture

JavaScript

MagicLamp.rub => load
MagicLamp.wish => load
MagicLamp.massage => preload
MagicLamp.wishForMoreWishes => preload
MagicLamp.polish => clean

Rake Tasks

rake mlfn => rake magic_lamp:fixture_names
rake mll => rake magic_lamp:lint

Contributing

  1. Fork it
  2. Clone it locally
  3. cd into the project root
  4. ruby bootstrap
  5. appraisal install
  6. Run the specs with appraisal rake
  7. Update the CHANGELOG.md
  8. Create your feature branch (git checkout -b my-new-feature)
  9. Commit your changes (git commit -am 'Add some feature')
  10. Push to the branch (git push origin my-new-feature)
  11. Create new Pull Request

magic_lamp's People

Contributors

crismali avatar edouard-chin avatar lazylester avatar spastorino avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

magic_lamp's Issues

Error with all_fixtures.js

This line

<% json = MagicLamp.generate_all_fixtures.to_json rescue nil %>

Always returns nil. So there is no opportunity to load all_fixtures json.

fixture loaded, inside document ready, $() returns undefined

I use MagicLamp to load my rails view. However my $('selector') query returns undefined inside document ready or specially called after fixture loaded.

If fixture loaded with jasmine, spec runs without problem.

What would be the problem? Please help.

Inline javascript - method does not exists

I'm loading a fixture with a layout that yields a content block :scripts at the bottom. The :scripts content block contains some inline javascript that I set in a partial - something like this:

<% content_for :scripts do %>
<script>
    var goTo = function(path){
        window.location.href = path;
    }

    $('body').on('click', function(){
        goTo("/");
    });
</script>
<% end %>

This works great in my app but when I run my tests the goTo function does not exist, however, the functions in application.js are all there. How can I fix this?

Asset precompilation in engine.rb

Getting errors with MagicLamp when trying to navigate to /magic_lamp due to asset precompilation not being set up. It should probably be set up in engine.rb of MagicLamp itself instead of client projects. I can submit a PR if you like?

Wrap register_fixture blocks in an ActiveRecord transaction

This way you could use ActiveRecord::Base#create and FactoryGirl.create and not worry about polluting your development db. Plus all of the create callbacks work. Should be able to opt out though (at the individual fixture level and globally).

Error with rails 5 url_helpers

When we run the lint method to check the magic_lamp is properly rendering our templates, it is breaking on the url_helpers (link_to for a show page) by not grabbing the id that is passed to it. The page works fine when magic lamp is not involved. So the issue is why does the url helper think the id is nil? Sorry I'm still pretty new to this, thanks for your help!

Here's the error:
Error: ActionView::Template::Error: No route matches {:action=>"show", :controller=>"metros", :id=>nil} missing required keys: [:id]

Lamp file:
`MagicLamp.fixture(controller: CaboodlesController) do

  @metro = {"id": 4}
  render 'caboodles/testing'

end`

Routes:
get 'caboodles/testing/:id' => 'caboodles#testing', as: 'testing' resources :metros, only: :show

Url_Helper in "/views/caboodles/testing.html.haml":
=link_to 'Back to Metro, metro_path(id: @metro['id'])

Edit
When we don't use link_to, but we use something like this:

%a{href: "/metros/#{@metro['id']}"} Back to Metro

the lint passes, and the view is properly rendered by magic lamp.

404 Response does not make Magic Lamp JS throw an error

The Magic Lamp JS only throws errors when it receives a 400 or 500 response exactly. It should be able to handle 404s at least. Not sure if it should give the generic error message 500s give or something more detailed.

Loading fixtures for namespaced controllers and views

I have a project that uses Rails namespacing. I want to test my SpendersController, which is namespaced under manage_access, so the file lives in app/controllers/manage_access/spenders_controller.rb. I want to load the index view, at app/views/manage_access/spenders/index.html.erb.

I can't figure out what to pass to the controller param in the call to fixture to have it find this namespaced controller.

Magic Lamp and Teaspoon are not friends ;)

So, if I have 250 tests (prior to using magic lamp).

I introduce magic lamp to the "first test".

It appears that the fixture magic lamp put in, "lasts forever".

I have:

<select id="orgSelector">
  <option>1</option>
  <option>2</option>
</select>

(to code-paraphrase).

So in mny FIRST test, it looks for $("#orgSelector").find('option') and sees there are 2 of them.

Then, 155 tests later, I have a fixture with

<select id="orgSelector">
  <option>1</option>
  <option>2</option>
...
  <option>17</option>
</select>

if I do r $("#orgSelector").find('option'), it finds that it has 2 options (even though the fixture in test 150 -- which is NOT magic lamp based, but just uses the jasmine test fixture loaded to pull a html file from disk)
CLEARLY has 17).

Thoughts?

Missing something trivial :)

So I have a page with the following setup:

/dashboard/index.html.erb

that file, of course, loads some partials
/dashboard/_widget1.html.erb
/dashboard/_widget2.html.erb

so if I do:

MagicLamp.register_fixture do
  @organizations = [Organization.new(id: 1, name: 'foo')]
  render "dashboard/index"
end

Then do MagicLamp.load('dashboard/index') it will crash, because it has no idea what _widget1 etc is.

Error: ActionView::Template::Error: Missing partial application/_widget1 with {:locale=>[:en], :formats=>[:html, :text, :js, :css, :ics, :csv, :vcf, :png, :jpeg, :gif, :bmp, :tiff, :mpeg, :xml, :rss, :atom, :yaml, :multipart_form, :url_encoded_form, :json, :pdf, :zip], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :arb, :jbuilder]}.

What's the trick? (which i'm guessing is obvious, and possibly even in the docs but I missed it).

Thanks!

stylesheets loaded after document ready

I'm testing the js on a page generated by a rails controller.

MagicLamp loads the page (it seems, correct me if I'm wrong) into a wrapper page of its own. This seems reasonable.

However by using this technique, the stylesheets from my page are loaded after the browser declares "document ready". Whereas in normal operation, stylesheets are loaded before document ready if there is javascript on the page. So a js test that involves the dom may not return the correct result (in my case it sometimes passes and sometimes fails, depending on how quickly the stylesheet is delivered by the server).

I've poked around the code to see where I could fix this, but it seems to be a fundamental characteristic of the architecture.

Any tips on where to fix this?

How to get magic_lamp and factory_bot to work together?

I've got magic_lamp working with a simple fixture and a mocha spec. However, I'd really like to DRY things up and use factory_bot to setup the fixture. I've tried requiring 'support/factory_bot' in different places to no avail.

How are you meant to do this?

rake magic_lamp:lint complains with:

Error: NoMethodError: undefined method 'create' for #<RainboxesController:0x00007fa153e50be0>

magic_lamp.rb

MagicLamp.fixture(controller: RainboxesController) do
  create(:rainbox)
  render "index"
end

magic_lamp_config.rb

#Simply load your helpers in the magic_lamp_config.rb file like so:
Dir[Rails.root.join("spec", "support", "magic_lamp_helpers/**/*.rb")].each { |f| load f }

require "database_cleaner"

MagicLamp.configure do |config|

  DatabaseCleaner.strategy = :transaction

  config.before_each do
    DatabaseCleaner.start
  end

  config.after_each do
    DatabaseCleaner.clean
  end
end

missing example app

Thanks for magic_lamp, Michael. Looks like it's going to be a great help in my js testing.

In the readme, in last line of the the section titled "A few more examples", the link to "here's an example app" is broken. If that example app is still available, would it be possible to fix the link, please.
cheers, Les

How do I use Magic Lamp to render cells?

In our project we're using Cells to render html strings instead of the ActionView stack in a lot of cases... It works almost the same, pass in an instance that the cell treats as it's model and it will spit out the html. It's a ViewModel for Rails essentially.

The point being that we're not using controllers explicitly in all cases to render certain components of the app.

Is there a way to define fixtures that simply pass an instance variable into a cell and use that for the html instead of the ActionView render method?

In most cases we wouldn't even need a request / response cycle since the cells spit out stuff based on just a PORO. Some of them do need a current_user context though so we'll have to figure out how to get around that...

JSON fixtures

This is a feature request. It would be nice to also create json fixtures with magic_lamp so you could avoid stubbing json responses in js specs.

Probably a simple thing I can't figure out

if I have something like:

MagicLamp.register_fixture(controller:ShoppingController, extend: AuthStub) do
  render :show
end

How do I specify different things for format json, vs html vs pdf etc?

Sprockets caches `all_fixtures`

This forces the user to have to blow away tmp every time they change a fixture. Need to find a way to either configure or otherwise hook into sprockets to prevent this caching for Magic Lamp.

Webpacker compatibility (question)

I'm trying to get my head around how to compile and load my javascript to the test template in a webpacker environment. I'm having little success figuring it out. Can you provide any tips, please? (Edit:) Maybe it's handled in teaspoon?

Magic Lamp and RAILS_ENV=test

I didn’t see this in the docs.

So — everything works perfectly… except! (has to be one of those right?)

if I do RAILS_ENV=test before running teaspoon , or do RAILS_ENV=test rake magic_lamp:lint I get:

Error: ActionView::Template::Error: called redirect_to while creating a fixture, this is probably not what you want to have happen.

Is magic lamp “intended” to run with a test rails_env, or only development?

Trying to decipher an error

So i've been converting tests over happily.. I get errors doing magic_lamp/lint, they make sense, I fix them.

Now i'm getting an error I can't seem to decipher at all:

Error: NameError: undefined local variable or method `null' for #<NotificationsSettingsController:0x007ffd29f08588> 

It isn't complaining about a missing @ in the template etc (the standard error).. and I can't find any way to debug/breakpoint/make sense of the above error

I tried starting up rails in debug mode and setting breakpoints, but they don't even "stop" (in the actual controller code). So, sort of at a loss haha.

Any hints/help would be appreciated :)

Rendering Layouts?

MagicLamp.register_fixture(name: "homepage", controller: HomeController) do
  render template: "home/index"
end

Is only rendering the <% yield %> section of the template, how do we get it to render the entire layout?

Form for with symbols breaks form rendering

= form_for :foo do
  ...

This form of form_for seems to break the routing. The above throws an error which can be fixed with:

= form_for :for, url: "" do
  ...

This is obviously not ideal.

lamp files not loading in order; module not found

So we had Mocha + Teaspoon + MagicLamp working smooth on CodeShip, but our monolithic magic_lamp.rb file was getting a bit out of hand.

Tests are passing fine on CodeShip, here:

codeship_cruising

We broke up the single file into several using the MagicLamp docs:

codeship_cruising_2

Locally, tests passed without a problem:

1__bash

But CodeShip hit an iceberg:

codeship_sinks_1

codeship_sinks_2

Any thoughts on why the CodeShip environment would have trouble loading separate MagicLamp files while localhost is smooth sailing?

Handle undeffing helpers

Say you have a helper module in magic_lamp_config.rb or required in magic_lamp_config.rb, when the config is loaded it should be able to undef those module to prevent hold over state from previous requests. That is, if you update AuthStub to not have a method any more, it should not have that method any more and you shouldn't have to bounce the server to make that happen.

javascript loaded before template

Magic Lamp v1.0.0
Teaspoon 1.1.5
teaspoon-jasmine 2.3.4
rails 3.2.11

I have a site and I'm trying to add in a testing framework. I have this JS in my application(not in my application js, but added in on a certain page)

$j(function() {                                                                                                                                                                                   
  $j('#projectReportsSelect').on('change', function(event) {                                                                                                                                      
    var selected_option = $j(this).find('option:selected');                                                                                                                                       
    if(selected_option.val()) {                                                                                                                                                                   
      var form = $j('#projectReportsForm');                                                                                                                                                       
      form.submit();                                                                                                                                                                              
    } else {                                                                                                                                                                                      
      var report_section = $j('#projectReportDiv');                                                                                                                                               
      report_section.hide( "slide", { direction: 'up' }, 1000, function() { report_section.html(""); });                                                                                          
    }                                                                                                                                                                                             
  });                                                                                                                                                                                  
});  

So after fighting a little while, I finally get the partial rendered using magic lamp and here is my spec:

//= require projects                                                                                                                                                                              
describe("My great feature", function() {                                                                                                                                                         

  beforeEach(function() {                                                                                                                                                                         
    MagicLamp.load("projects/reports");                                                                                                                                                           
  });                                                                                                                                                                                             

  it("will change the world", function() {                                                                                                                                                        
    expect(true).toBe(true);                                                                                                                                                                      
    expect(jQuery).toBeDefined();                                                                                                                                                                 
  });                                                                                                                                                                                                                                                                                                                                                                                            
});

My problem is that

 $j('#projectReportsSelect').on('change', function(event) {

is executed before my template is loaded.

Any suggestions on how to work around this or work with this? Am I doing this wrong?

Devise issue with devise_mapping

I think I have everything setup right but now Im running into Devise issues. @crismali I saw you mentioned in other issues that working around Devise was a bit tricky but unfortunately I wasn't able to find anything after hours of looking. Do you have anything that could point me in the right direction?

To get a proof of concept I tried to make a fixture out of the login page (no Devise is what I was thinking) but it looks like Im still getting a Devise related problems.

Here's what Im getting when attempting to go here http://localhost:3000/magic_lamp/lint -
Error: ActionView::Template::Error: undefined method 'name' for nil:NilClass /Users/ryangrush/.rvm/gems/ruby-2.2.5@company/gems/devise-3.5.10/app/controllers/devise_controller.rb:38:in 'resource_name'

registrations_new_lamp.rb

MagicLamp.fixture(controller: Users::SessionsController, name: "something", extend: AuthStub) do
  render template: "devise/sessions/new"
end

auth_stub.rb

module AuthStub
  def current_user
    @current_user ||= User.create!(
      email: "[email protected]",
      encrypted_password: "$2a$10$3OF9YyLG6DudmeIUtIlnX2usIFYhAJ77pep5y93BLuSuu",
      first_name: 'Tom',
      last_name: 'Smith',
      onboarded_status: 'car_verified'
    )
  end
end

and my SessionsController inherits from Devise -

sessions_controller.rb

class Users::SessionsController < Devise::SessionsController

magic_lamp_config.rb

MagicLamp.configure do |config|

  Dir[Rails.root.join("spec", "javascripts", "support", "magic_lamp_helpers/**/*.rb")].each { |f| load f }

  # if you want to require the name parameter for the 'fixture' method
  config.infer_names = false

  config.global_defaults = { extend: AuthStub }

  config.before_each do
    puts "I appear before the block passed to 'fixture' executes!"
  end

  config.after_each do
    puts "I appear after the block passed to 'fixture' executes!"
  end

end

Line 36-40 of the DeviseController in the Devise gem -

  # Proxy to devise map name
  def resource_name
    devise_mapping.name
  end
  alias :scope_name :resource_name

Render JSON

Right now you can render json or arbitrary strings if render is not called in a fixture block. But, calling render json: { foo: "bar" } breaks when it probably shouldn't. It should just work. You should probably also be able to render XML or whatever you want. That is, render foo: @bar tries to call to_foo on @bar. render text: "foo" probably works already.

A good use case for this is if you want to call some controller method that already calls render to render your fixture. Like:

# controller
def shared_method
  render json: @foo.select(&:some_operation_you_would_rather_not_duplicate_in_the_fixtures)
end

Magic Lamp should probably also throw an error if redirect_to is called or if render is called twice.

Improve Rails JavaScript spec runner support

After adding a rough version of magic_lamp/all_fixtures.js.erb on top of the current xhr support, most of these should be supported. The ones that are already checked off work on master at the moment.

  • Teaspoon
  • Konacha
  • Jasmine Rails
  • Evergreen
  • Jasmine

undefined method `define' for MagicLamp:Module

Following the 'Drying up your fixtures' example showing on the readme, I got the error message as shown in the title. Here is my code

#magic_lamp.rb
MagicLamp.define(controller: OrdersController) do
  fixture(name: "order_index") do
    @orders = Order.all
    render :index
  end
end

Anyone can help? thanks.

Repackage gems without giant log files

The gems that are currently distributed on rubygems.org have enormous log files included:

vagrant@vagrant:~/.gem/ruby/2.1.5/gems/magic_lamp-1.5.0$ du -hs *
124K    app
8.0K    config
60K lib
12K LICENSE
20K README.md
122M    spec

The worst offender is spec/dummy/log/test.log which rings in at 96M. @crismali can you repackage the 1.5.0 gem (not sure about the others) with a git clean -dfprior to packaging them?

Loading helper modules

Should probably document that helper modules should be loaded in the config file. Could also add a support path option that would load a given directory or list of files or something before loading fixtures. It could also be included as part of the lint process too. This would help prevent issues like #13 before they even happen.

Document nested resources

When rails is inferring routes sometimes you need to mess with request.env["action_dispatch.request.path_parameters"]. When the route is nested with with a parameter in the url like /orders/:order_id/foos you need to add the :order_id to it like so:

request.env["action_dispatch.request.path_parameters"] = { 
  action: "index", 
  controller: "foos", 
  order_id: 3 
}

Better Linting

A better lint task would:

  • tell me which fixtures specifically are broken and how
  • allow me to lint just one fixture if I wanted to
  • tell me if the linting failed at the name inference step or when actually rendering the template

It would also be awesome if I could just visit /magic_lamp/lint and see my what is wrong with my fixtures in the browser. If everything was fine it could display all of the fixture names.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.