Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run Jasmine specs #32

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/channels/application_cable/channel.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module ApplicationCable
class Channel < ActionCable::Channel::Base
class Channel
end
end
29 changes: 29 additions & 0 deletions app/channels/hotwire/jasmine/suites_channel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
module Hotwire
module Jasmine
class SuitesChannel < ActionCable::Channel::Base
def jasmine_started(data)
Hotwire::Jasmine::SuiteFinder.find(data['suiteId']).jasmine_started(data)
end

def jasmine_suite_started(data)
Hotwire::Jasmine::SuiteFinder.find(data['suiteId']).jasmine_suite_started(data)
end

def jasmine_spec_started(data)
Hotwire::Jasmine::SuiteFinder.find(data['suiteId']).jasmine_spec_started(data)
end

def jasmine_spec_done(data)
Hotwire::Jasmine::SuiteFinder.find(data['suiteId']).jasmine_spec_done(data)
end

def jasmine_suite_done(data)
Hotwire::Jasmine::SuiteFinder.find(data['suiteId']).jasmine_suite_done(data)
end

def jasmine_done(data)
Hotwire::Jasmine::SuiteFinder.find(data['suiteId']).jasmine_done(data)
end
end
end
end
1 change: 1 addition & 0 deletions app/controllers/hotwire/jasmine/application_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
class Hotwire::Jasmine::ApplicationController < ActionController::Base; end
11 changes: 11 additions & 0 deletions app/controllers/hotwire/jasmine/suites_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class Hotwire::Jasmine::SuitesController < Hotwire::Jasmine::ApplicationController
def index
@suites = Hotwire::Jasmine::SuiteFinder.resolve
end

def show
@suite = Hotwire::Jasmine::SuiteFinder.find(params[:id])
rescue KeyError
raise ActiveRecord::RecordNotFound, params[:id]
end
end
3 changes: 3 additions & 0 deletions app/javascript/hotwire/jasmine/application.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails"
import "hotwire/jasmine/controllers"
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Controller } from '@hotwired/stimulus'
import { createConsumer } from '@rails/actioncable'
const consumer = createConsumer()

export default class extends Controller {
connect() {
this.channel = consumer.subscriptions.create({channel: 'Hotwire::Jasmine::SuitesChannel'})
}

disconnect() {
this.channel.disconnect()
}

post({type, detail}) {
this.channel.perform(type.replaceAll(':', '_'), detail)
}
}
9 changes: 9 additions & 0 deletions app/javascript/hotwire/jasmine/controllers/application.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Application } from '@hotwired/stimulus'

const application = Application.start()

// Configure Stimulus development experience
application.debug = false
window.Stimulus = application

export { application }
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
receive({data: {type, detail}}) {
const event = new CustomEvent(type, {detail, bubbles: true})
this.element.dispatchEvent(event)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Controller } from '@hotwired/stimulus'

export default class extends Controller {
post(event) {
const {type, detail} = event
window.parent.postMessage({type, detail}, "*")
}
}
7 changes: 7 additions & 0 deletions app/javascript/hotwire/jasmine/controllers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Import and register all your controllers from the importmap under controllers/*

import { application } from "hotwire/jasmine/controllers/application"

// Eager load all controllers defined in the import map under controllers/**/*_controller
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
eagerLoadControllersFrom("hotwire/jasmine/controllers", application)
74 changes: 74 additions & 0 deletions app/javascript/hotwire/jasmine/controllers/suite_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { Controller } from '@hotwired/stimulus'
import jasmineRequire from 'jasmine-core/lib/jasmine-core/jasmine.js'

export default class extends Controller {
static values = {id: String}

initialize() {
this.jasmine = jasmineRequire.core(jasmineRequire);
}

async connect() {
const { jasmine, idValue } = this;
const global = jasmine.getGlobal();
global.jasmine = jasmine;
const env = jasmine.getEnv();
const jasmineInterface = jasmineRequire.interface(jasmine, env);

env.addReporter(this);

for (const property in jasmineInterface) {
global[property] = jasmineInterface[property];
}

try {
await import(idValue);
await env.execute();
} finally {
env.clearReporters();
for (const property in jasmineInterface) {
delete global[property];
}
}
}

jasmineStarted({order, ...detail}) {
const { idValue } = this;
this.stack = [];
const event = new CustomEvent('jasmine:started', {detail: {suiteId: idValue, ...detail}, bubbles: true});
this.element.dispatchEvent(event);
}

suiteStarted({order, ...detail}) {
const { idValue, stack } = this;
stack.push(detail)
const event = new CustomEvent('jasmine:suite:started', {detail: {suiteId: idValue, ...detail}, bubbles: true});
this.element.dispatchEvent(event);
}

specStarted({order, ...detail}) {
const { idValue, stack } = this;
const event = new CustomEvent('jasmine:spec:started', {detail: {suiteId: idValue, stack, ...detail}, bubbles: true});
this.element.dispatchEvent(event);
}

specDone({order, ...detail}) {
const { idValue, stack } = this;
const event = new CustomEvent('jasmine:spec:done', {detail: {suiteId: idValue, stack, ...detail}, bubbles: true});
this.element.dispatchEvent(event);
}

suiteDone({order, ...detail}) {
const { idValue, stack } = this;
stack.pop();
const event = new CustomEvent('jasmine:suite:done', {detail: {suiteId: idValue, ...detail}, bubbles: true});
this.element.dispatchEvent(event);
}

jasmineDone({order, ...detail}) {
const { idValue } = this;
this.stack = null;
const event = new CustomEvent('jasmine:done', {detail: {suiteId: idValue, ...detail}, bubbles: true});
this.element.dispatchEvent(event);
}
}
11 changes: 11 additions & 0 deletions app/views/hotwire/jasmine/suites/_suite.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div class='jasmine_html-reporter'>
<div class='jasmine-banner'>
<a class='jasmine-title' href='http://jasmine.github.io/' target='_blank'></a>
<span class='jasmine-version'></span>
</div>
<ul class='jasmine-symbol-summary'></ul>
<div class='jasmine-alert'></div>
<div class='jasmine-results'>
<div class='jasmine-failures'></div>
</div>
</div>
8 changes: 8 additions & 0 deletions app/views/hotwire/jasmine/suites/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<%= turbo_stream_from 'hotwire_jasmine' %>
<%= turbo_frame_tag 'hotwire_jasmine' do %>
<%= render partial: 'suite', locals: {suites: @suites} %>
<% end %>

<% @suites.each do |suite| %>
<%= content_tag(:iframe, nil, id: suite.id.parameterize, style: 'display: none;', loading: :eager, src: hotwire_jasmine_suite_path(suite.id), data: {controller: 'actioncable-reporter iframe-client', action: 'message@window->iframe-client#receive jasmine:started->actioncable-reporter#post jasmine:suite:started->actioncable-reporter#post jasmine:spec:started->actioncable-reporter#post jasmine:spec:done->actioncable-reporter#post jasmine:suite:done->actioncable-reporter#post jasmine:done->actioncable-reporter#post'}) %>
<% end %>
1 change: 1 addition & 0 deletions app/views/hotwire/jasmine/suites/show.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= content_tag(:template, nil, data: {controller: 'suite iframe-host', suite_id_value: @suite.id, action: 'jasmine:started->iframe-host#post jasmine:suite:started->iframe-host#post jasmine:spec:started->iframe-host#post jasmine:spec:done->iframe-host#post jasmine:suite:done->iframe-host#post jasmine:done->iframe-host#post'}) %>
20 changes: 20 additions & 0 deletions app/views/layouts/hotwire/jasmine/application.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="<%= I18n.locale %>">
<head>
<title>Jasmine</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= javascript_inline_importmap_tag(JSON.pretty_generate(JSON.parse(Rails.application.importmap.to_json(resolver: self)).deep_merge('imports' => Hotwire::Jasmine::SuiteFinder.resolve.map(&:to_h).reduce(:+)))) %>
<%= javascript_importmap_module_preload_tags %>
<%= javascript_module_preload_tag(Hotwire::Jasmine::SuiteFinder.resolve.map(&:to_h).reduce(:+).values) %>
<%= javascript_importmap_shim_nonce_configuration_tag %>
<%= javascript_importmap_shim_tag %>
<%= javascript_import_module_tag('hotwire/jasmine/application') %>
<%= action_cable_meta_tag %>
<%= stylesheet_link_tag 'https://ga.jspm.io/npm:[email protected]/lib/jasmine-core/jasmine.css' %>
</head>
<body>
<%= yield %>
</body>
</html>
1 change: 1 addition & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
module Retrospectives
class Application < Rails::Application
config.load_defaults 7.0
config.autoload_paths << config.root.join('lib')
config.generators do |g|
g.helper false
g.assets false
Expand Down
13 changes: 9 additions & 4 deletions config/importmap.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Pin npm packages by running ./bin/importmap

pin '@hotwired/stimulus', to: 'https://ga.jspm.io/npm:@hotwired/[email protected]/dist/stimulus.js'
pin '@hotwired/stimulus', to: 'stimulus.min.js', preload: true
pin '@hotwired/stimulus-loading', to: 'stimulus-loading.js', preload: true
pin '@hotwired/turbo-rails', to: 'turbo.min.js', preload: true
pin 'application'
pin 'canvas-confetti', to: 'https://ga.jspm.io/npm:[email protected]/dist/confetti.module.mjs'
pin 'hotkeys-js', to: 'https://ga.jspm.io/npm:[email protected]/dist/hotkeys.esm.js'
pin 'stimulus-dropdown', to: 'https://ga.jspm.io/npm:[email protected]/dist/stimulus-dropdown.es.js'
pin 'stimulus-clipboard', to: 'https://ga.jspm.io/npm:[email protected]/dist/stimulus-clipboard.es.js'
Expand All @@ -13,7 +14,11 @@
pin 'stimulus-timeago', to: 'https://ga.jspm.io/npm:[email protected]/dist/stimulus-timeago.es.js'
pin 'stimulus-use', to: 'https://ga.jspm.io/npm:[email protected]/dist/index.js'
pin 'tailwindcss-stimulus-components', to: 'https://ga.jspm.io/npm:[email protected]/dist/tailwindcss-stimulus-components.modern.js'

pin 'application', preload: true
pin_all_from 'app/javascript/controllers', under: 'controllers'
pin 'canvas-confetti', to: 'https://ga.jspm.io/npm:[email protected]/dist/confetti.module.mjs'
pin_all_from 'spec/javascript', to: 'spec/javascript'

pin_all_from 'app/javascript/hotwire/jasmine/controllers', under: 'hotwire/jasmine/controllers'
pin 'hotwire/jasmine/application', preload: true
pin 'jasmine-core/lib/jasmine-core/jasmine.js', to: 'https://ga.jspm.io/npm:[email protected]/lib/jasmine-core/jasmine.js'
pin 'process', to: 'https://ga.jspm.io/npm:@jspm/[email protected]/nodelibs/browser/process-production.js'
pin '@rails/actioncable', to: 'https://ga.jspm.io/npm:@rails/[email protected]/app/assets/javascripts/actioncable.esm.js'
6 changes: 1 addition & 5 deletions config/initializers/assets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,4 @@

# Add additional assets to the asset load path.
# Rails.application.config.assets.paths << Emoji.images_path

# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in the app/assets
# folder are already added.
# Rails.application.config.assets.precompile += %w( admin.js admin.css )
Rails.application.config.assets.paths << 'spec/javascript'
7 changes: 7 additions & 0 deletions config/initializers/hotwire_jasmine.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
require 'hotwire/jasmine'

Hotwire::Jasmine.configure do |config|
config.paths << Rails.root.join('spec/javascript')
end

Rails.application.config.hotwire_jasmine_store = ActiveSupport::Cache.lookup_store(:file_store, Rails.root.join('tmp/hotwire/stimulus'))
11 changes: 11 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
Rails.application.routes.draw do
namespace :hotwire do
namespace :jasmine do
resources :suites, only: [:index, :show], id: /.+/ do
resources :specs, only: [:update]
end
end
end

mount Rack::File.new(Rails.root.join('spec/javascript')) => '/spec/javascript'
mount Rack::File.new(Rails.root.join('spec/fixtures/jasmine')) => '/spec/fixtures/jasmine'

devise_for :users, controllers: {omniauth_callbacks: 'users/omniauth_callbacks'}

resources :boards do
Expand Down
14 changes: 14 additions & 0 deletions lib/hotwire/jasmine.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require 'hotwire/jasmine/configuration'
require 'hotwire/jasmine/suite'

module Hotwire
module Jasmine
def self.configuration
Hotwire::Jasmine::Configuration.instance
end

def self.configure(&block)
yield(configuration) if block
end
end
end
13 changes: 13 additions & 0 deletions lib/hotwire/jasmine/configuration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module Hotwire
module Jasmine
class Configuration
include Singleton

attr_accessor :paths

def initialize(paths: [])
@paths = Array(paths)
end
end
end
end
69 changes: 69 additions & 0 deletions lib/hotwire/jasmine/suite.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
require 'hotwire/jasmine/suite_finder'

module Hotwire
module Jasmine
class Suite
attr_reader :path

def initialize(path:)
@path = path
end

def id
path.dirname.join(basename).to_s
end

def to_h
{id => "/#{path}"}
end

def done?
data['done']
end

def data
Rails.application.config.hotwire_jasmine_store.fetch(id) { cache_defaults }
end

def jasmine_started(result)
Rails.application.config.hotwire_jasmine_store.delete(id)
suite = data
suite['totalSpecsDefined'] = result['totalSpecsDefined']
Rails.application.config.hotwire_jasmine_store.write(id, suite)
end

def jasmine_suite_started(_)
end

def jasmine_spec_started(_)
end

def jasmine_spec_done(result, *args)
suite = data
suite[result['status']] ||= []
suite[result['status']].push(result)
Rails.application.config.hotwire_jasmine_store.write(id, suite)
end

def jasmine_suite_done(_)
end

def jasmine_done(_)
suite = Rails.application.config.hotwire_jasmine_store.fetch(id) { {'done' => false} }
Rails.application.config.hotwire_jasmine_store.write(id, suite.merge('done' => true))
end

private

def cache_defaults
{'done' => false, 'totalSpecsDefined' => 0}
end

def basename
return path.basename('.js') if path.extname.eql?('.js')

path.basename
end
end
end
end
Loading