mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-27 09:36:19 -05:00
Migrate all jasmine specs to Qunit. Removed Jasmine.
This commit is contained in:
parent
e263bb3c0a
commit
8c4aac7f94
24 changed files with 401 additions and 659 deletions
2
Gemfile
2
Gemfile
|
@ -103,10 +103,8 @@ group :test, :development do
|
||||||
gem 'certified', require: false
|
gem 'certified', require: false
|
||||||
gem 'fabrication', require: false
|
gem 'fabrication', require: false
|
||||||
gem 'qunit-rails'
|
gem 'qunit-rails'
|
||||||
gem 'guard-jasmine', require: false
|
|
||||||
gem 'guard-rspec', require: false
|
gem 'guard-rspec', require: false
|
||||||
gem 'guard-spork', require: false
|
gem 'guard-spork', require: false
|
||||||
gem 'jasminerice'
|
|
||||||
gem 'mocha', require: false
|
gem 'mocha', require: false
|
||||||
gem 'rb-fsevent', require: RUBY_PLATFORM =~ /darwin/i ? 'rb-fsevent' : false
|
gem 'rb-fsevent', require: RUBY_PLATFORM =~ /darwin/i ? 'rb-fsevent' : false
|
||||||
gem 'rb-inotify', '~> 0.9', require: RUBY_PLATFORM =~ /linux/i ? 'rb-inotify' : false
|
gem 'rb-inotify', '~> 0.9', require: RUBY_PLATFORM =~ /linux/i ? 'rb-inotify' : false
|
||||||
|
|
19
Gemfile.lock
19
Gemfile.lock
|
@ -151,13 +151,6 @@ GEM
|
||||||
clockwork (0.5.0)
|
clockwork (0.5.0)
|
||||||
tzinfo (~> 0.3.35)
|
tzinfo (~> 0.3.35)
|
||||||
coderay (1.0.9)
|
coderay (1.0.9)
|
||||||
coffee-rails (3.2.2)
|
|
||||||
coffee-script (>= 2.2.0)
|
|
||||||
railties (~> 3.2.0)
|
|
||||||
coffee-script (2.2.0)
|
|
||||||
coffee-script-source
|
|
||||||
execjs
|
|
||||||
coffee-script-source (1.6.2)
|
|
||||||
connection_pool (1.0.0)
|
connection_pool (1.0.0)
|
||||||
daemons (1.1.9)
|
daemons (1.1.9)
|
||||||
debug_inspector (0.0.2)
|
debug_inspector (0.0.2)
|
||||||
|
@ -206,11 +199,6 @@ GEM
|
||||||
lumberjack (>= 1.0.2)
|
lumberjack (>= 1.0.2)
|
||||||
pry (>= 0.9.10)
|
pry (>= 0.9.10)
|
||||||
thor (>= 0.14.6)
|
thor (>= 0.14.6)
|
||||||
guard-jasmine (1.15.1)
|
|
||||||
childprocess
|
|
||||||
guard (>= 1.1.0)
|
|
||||||
multi_json
|
|
||||||
thor
|
|
||||||
guard-jshint-on-rails (0.0.2)
|
guard-jshint-on-rails (0.0.2)
|
||||||
guard (>= 1.0.0)
|
guard (>= 1.0.0)
|
||||||
jshint_on_rails (>= 1.0.2)
|
jshint_on_rails (>= 1.0.2)
|
||||||
|
@ -221,8 +209,6 @@ GEM
|
||||||
childprocess (>= 0.2.3)
|
childprocess (>= 0.2.3)
|
||||||
guard (>= 1.1)
|
guard (>= 1.1)
|
||||||
spork (>= 0.8.4)
|
spork (>= 0.8.4)
|
||||||
haml (4.0.2)
|
|
||||||
tilt
|
|
||||||
handlebars-source (1.0.0.rc4)
|
handlebars-source (1.0.0.rc4)
|
||||||
has_ip_address (0.0.1)
|
has_ip_address (0.0.1)
|
||||||
hashie (2.0.4)
|
hashie (2.0.4)
|
||||||
|
@ -239,9 +225,6 @@ GEM
|
||||||
image_size (1.1.2)
|
image_size (1.1.2)
|
||||||
image_sorcery (1.1.0)
|
image_sorcery (1.1.0)
|
||||||
in_threads (1.1.1)
|
in_threads (1.1.1)
|
||||||
jasminerice (0.0.10)
|
|
||||||
coffee-rails
|
|
||||||
haml
|
|
||||||
journey (1.0.4)
|
journey (1.0.4)
|
||||||
jshint_on_rails (1.0.2)
|
jshint_on_rails (1.0.2)
|
||||||
json (1.7.7)
|
json (1.7.7)
|
||||||
|
@ -502,7 +485,6 @@ DEPENDENCIES
|
||||||
fast_xs
|
fast_xs
|
||||||
fastimage
|
fastimage
|
||||||
fog
|
fog
|
||||||
guard-jasmine
|
|
||||||
guard-jshint-on-rails
|
guard-jshint-on-rails
|
||||||
guard-rspec
|
guard-rspec
|
||||||
guard-spork
|
guard-spork
|
||||||
|
@ -512,7 +494,6 @@ DEPENDENCIES
|
||||||
hiredis
|
hiredis
|
||||||
image_optim
|
image_optim
|
||||||
image_sorcery
|
image_sorcery
|
||||||
jasminerice
|
|
||||||
jshint_on_rails
|
jshint_on_rails
|
||||||
librarian (>= 0.0.25)
|
librarian (>= 0.0.25)
|
||||||
listen
|
listen
|
||||||
|
|
17
Guardfile
17
Guardfile
|
@ -3,23 +3,6 @@ require 'terminal-notifier-guard' if RUBY_PLATFORM.include?('darwin')
|
||||||
phantom_path = File.expand_path('~/phantomjs/bin/phantomjs')
|
phantom_path = File.expand_path('~/phantomjs/bin/phantomjs')
|
||||||
phantom_path = nil unless File.exists?(phantom_path)
|
phantom_path = nil unless File.exists?(phantom_path)
|
||||||
|
|
||||||
jasmine_options = {:phantomjs_bin => phantom_path, :server_env => :test}
|
|
||||||
|
|
||||||
if ENV['JASMINE_URL']
|
|
||||||
jasmine_options[:jasmine_url] = ENV['JASMINE_URL']
|
|
||||||
jasmine_options[:server] = :none
|
|
||||||
else
|
|
||||||
jasmine_options[:server] = :thin
|
|
||||||
jasmine_options[:port] = 8888
|
|
||||||
jasmine_options[:server_timeout] = 300
|
|
||||||
end
|
|
||||||
|
|
||||||
guard 'jasmine', jasmine_options do
|
|
||||||
watch(%r{spec/javascripts/spec\.js$}) { "spec/javascripts" }
|
|
||||||
watch(%r{spec/javascripts/.+_spec\.js$})
|
|
||||||
watch(%r{app/assets/javascripts/(.+?)\.js$}) { "spec/javascripts" }
|
|
||||||
end
|
|
||||||
|
|
||||||
# verify that we pass jshint
|
# verify that we pass jshint
|
||||||
# see https://github.com/MrOrz/guard-jshint-on-rails
|
# see https://github.com/MrOrz/guard-jshint-on-rails
|
||||||
guard 'jshint-on-rails', config_path: 'config/jshint.yml' do
|
guard 'jshint-on-rails', config_path: 'config/jshint.yml' do
|
||||||
|
|
|
@ -10,9 +10,6 @@ Discourse::Application.configure do
|
||||||
# Configure static asset server for tests with Cache-Control for performance
|
# Configure static asset server for tests with Cache-Control for performance
|
||||||
config.serve_static_assets = true
|
config.serve_static_assets = true
|
||||||
|
|
||||||
# Needed for jasmine specs to work
|
|
||||||
config.assets.debug = true
|
|
||||||
|
|
||||||
# Log error messages when you accidentally call methods on nil
|
# Log error messages when you accidentally call methods on nil
|
||||||
config.whiny_nils = true
|
config.whiny_nils = true
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ if defined?(Rack::MiniProfiler)
|
||||||
(env['PATH_INFO'] !~ /^\/message-bus/) &&
|
(env['PATH_INFO'] !~ /^\/message-bus/) &&
|
||||||
(env['PATH_INFO'] !~ /topics\/timings/) &&
|
(env['PATH_INFO'] !~ /topics\/timings/) &&
|
||||||
(env['PATH_INFO'] !~ /assets/) &&
|
(env['PATH_INFO'] !~ /assets/) &&
|
||||||
(env['PATH_INFO'] !~ /jasmine/) &&
|
(env['PATH_INFO'] !~ /qunit/) &&
|
||||||
(env['PATH_INFO'] !~ /users\/.*\/avatar/) &&
|
(env['PATH_INFO'] !~ /users\/.*\/avatar/) &&
|
||||||
(env['PATH_INFO'] !~ /srv\/status/) &&
|
(env['PATH_INFO'] !~ /srv\/status/) &&
|
||||||
(env['PATH_INFO'] !~ /commits-widget/)
|
(env['PATH_INFO'] !~ /commits-widget/)
|
||||||
|
@ -27,7 +27,7 @@ if defined?(Rack::MiniProfiler)
|
||||||
|
|
||||||
# without a user provider our results will use the ip address for namespacing
|
# without a user provider our results will use the ip address for namespacing
|
||||||
# with a load balancer in front this becomes really bad as some results can
|
# with a load balancer in front this becomes really bad as some results can
|
||||||
# be stored associated with ip1 as the user and retrieved using ip2 causing 404s
|
# be stored associated with ip1 as the user and retrieved using ip2 causing 404s
|
||||||
Rack::MiniProfiler.config.user_provider = lambda do |env|
|
Rack::MiniProfiler.config.user_provider = lambda do |env|
|
||||||
request = Rack::Request.new(env)
|
request = Rack::Request.new(env)
|
||||||
id = request.cookies["_t"] || request.ip || "unknown"
|
id = request.cookies["_t"] || request.ip || "unknown"
|
||||||
|
|
|
@ -37,7 +37,6 @@ The following Ruby Gems are used in Discourse:
|
||||||
* [rspec](https://rubygems.org/gems/rspec)
|
* [rspec](https://rubygems.org/gems/rspec)
|
||||||
* [shoulda](https://rubygems.org/gems/shoulda)
|
* [shoulda](https://rubygems.org/gems/shoulda)
|
||||||
* [turn](https://rubygems.org/gems/turn)
|
* [turn](https://rubygems.org/gems/turn)
|
||||||
* [jasminerice](https://rubygems.org/gems/jasminerice)
|
|
||||||
* [fabrication](https://rubygems.org/gems/fabrication)
|
* [fabrication](https://rubygems.org/gems/fabrication)
|
||||||
* [mocha](https://rubygems.org/gems/mocha)
|
* [mocha](https://rubygems.org/gems/mocha)
|
||||||
* [simplecov](https://rubygems.org/gems/simplecov)
|
* [simplecov](https://rubygems.org/gems/simplecov)
|
||||||
|
|
|
@ -1,221 +0,0 @@
|
||||||
/*global expect:true describe:true it:true beforeEach:true afterEach:true spyOn:true */
|
|
||||||
|
|
||||||
describe("Discourse.ClickTrack", function() {
|
|
||||||
|
|
||||||
var track = Discourse.ClickTrack.trackClick,
|
|
||||||
clickEvent,
|
|
||||||
html = [
|
|
||||||
'<div id="topic" id="1337">',
|
|
||||||
' <article data-post-id="42" data-user-id="3141">',
|
|
||||||
' <a href="http://www.google.com">google.com</a>',
|
|
||||||
' <a class="lightbox back quote-other-topic" href="http://www.google.com">google.com</a>',
|
|
||||||
' <a id="with-badge" data-user-id="314" href="http://www.google.com">google.com<span class="badge">1</span></a>',
|
|
||||||
' <a id="with-badge-but-not-mine" href="http://www.google.com">google.com<span class="badge">1</span></a>',
|
|
||||||
' <div class="onebox-result">',
|
|
||||||
' <a id="inside-onebox" href="http://www.google.com">google.com<span class="badge">1</span></a>',
|
|
||||||
' <a id="inside-onebox-forced" class="track-link" href="http://www.google.com">google.com<span class="badge">1</span></a>',
|
|
||||||
' </div>',
|
|
||||||
' <a id="same-site" href="http://discuss.domain.com">forum</a>',
|
|
||||||
' </article>',
|
|
||||||
'</div>'].join("\n");
|
|
||||||
|
|
||||||
var generateClickEventOn = function(selector) {
|
|
||||||
return $.Event("click", { currentTarget: $(selector)[0] });
|
|
||||||
}
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
$('body').html(html);
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(function() {
|
|
||||||
$('#topic').remove();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("lightboxes", function() {
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
clickEvent = generateClickEventOn('.lightbox');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not track clicks on lightboxes", function() {
|
|
||||||
expect(track(clickEvent)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not call preventDefault", function() {
|
|
||||||
spyOn(clickEvent, "preventDefault");
|
|
||||||
track(clickEvent);
|
|
||||||
expect(clickEvent.preventDefault).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it("calls preventDefault", function() {
|
|
||||||
clickEvent = generateClickEventOn('a');
|
|
||||||
spyOn(clickEvent, "preventDefault");
|
|
||||||
track(clickEvent);
|
|
||||||
expect(clickEvent.preventDefault).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not track clicks on back buttons", function() {
|
|
||||||
clickEvent = generateClickEventOn('.back');
|
|
||||||
expect(track(clickEvent)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not track clicks on quote buttons", function() {
|
|
||||||
clickEvent = generateClickEventOn('.quote-other-topic');
|
|
||||||
expect(track(clickEvent)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("removes the href and put it as a data attribute", function() {
|
|
||||||
clickEvent = generateClickEventOn('a');
|
|
||||||
track(clickEvent);
|
|
||||||
var $link = $('a').first();
|
|
||||||
expect($link.hasClass('no-href')).toBe(true);
|
|
||||||
expect($link.data('href')).toEqual("http://www.google.com");
|
|
||||||
expect($link.attr('href')).toBeUndefined();
|
|
||||||
expect($link.data('auto-route')).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("badges", function() {
|
|
||||||
|
|
||||||
it("does not update badge clicks on my own link", function() {
|
|
||||||
spyOn(Discourse.User, 'current').andReturn(314);
|
|
||||||
spyOn(Discourse, "get").andReturn(314);
|
|
||||||
|
|
||||||
track(generateClickEventOn('#with-badge'));
|
|
||||||
var $badge = $('span.badge', $('#with-badge').first());
|
|
||||||
expect(parseInt($badge.html(), 10)).toEqual(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("does not update badge clicks on links in my own post", function() {
|
|
||||||
spyOn(Discourse.User, 'current').andReturn(3141);
|
|
||||||
track(generateClickEventOn('#with-badge-but-not-mine'));
|
|
||||||
var $badge = $('span.badge', $('#with-badge-but-not-mine').first());
|
|
||||||
expect(parseInt($badge.html(), 10)).toEqual(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("oneboxes", function() {
|
|
||||||
|
|
||||||
it("does not update badge clicks in oneboxes", function() {
|
|
||||||
track(generateClickEventOn('#inside-onebox'));
|
|
||||||
var $badge = $('span.badge', $('#inside-onebox').first());
|
|
||||||
expect(parseInt($badge.html(), 10)).toEqual(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates badge clicks in oneboxes when forced", function() {
|
|
||||||
track(generateClickEventOn('#inside-onebox-forced'));
|
|
||||||
var $badge = $('span.badge', $('#inside-onebox-forced').first());
|
|
||||||
expect(parseInt($badge.html(), 10)).toEqual(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it("updates badge clicks", function() {
|
|
||||||
track(generateClickEventOn('#with-badge'));
|
|
||||||
var $badge = $('span.badge', $('#with-badge').first());
|
|
||||||
expect(parseInt($badge.html(), 10)).toEqual(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("right click", function() {
|
|
||||||
|
|
||||||
beforeEach(function(){
|
|
||||||
clickEvent = generateClickEventOn('a');
|
|
||||||
clickEvent.which = 3;
|
|
||||||
});
|
|
||||||
|
|
||||||
it("detects right clicks", function() {
|
|
||||||
expect(track(clickEvent)).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("changes the href", function() {
|
|
||||||
track(clickEvent);
|
|
||||||
var $link = $('a').first();
|
|
||||||
expect($link.attr('href')).toEqual("http://www.google.com");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("tracks external right clicks", function() {
|
|
||||||
Discourse.SiteSettings.track_external_right_clicks = true;
|
|
||||||
track(clickEvent);
|
|
||||||
var $link = $('a').first();
|
|
||||||
expect($link.attr('href')).toEqual("/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42");
|
|
||||||
// reset
|
|
||||||
Discourse.SiteSettings.track_external_right_clicks = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("new tab", function() {
|
|
||||||
|
|
||||||
beforeEach(function(){
|
|
||||||
clickEvent = generateClickEventOn('a');
|
|
||||||
spyOn(Discourse, 'ajax');
|
|
||||||
spyOn(window, 'open');
|
|
||||||
});
|
|
||||||
|
|
||||||
var expectItOpensInANewTab = function() {
|
|
||||||
expect(track(clickEvent)).toBe(false);
|
|
||||||
expect(Discourse.ajax).toHaveBeenCalled();
|
|
||||||
expect(window.open).toHaveBeenCalledWith('http://www.google.com', '_blank');
|
|
||||||
};
|
|
||||||
|
|
||||||
it("opens in a new tab when pressing shift", function() {
|
|
||||||
clickEvent.shiftKey = true;
|
|
||||||
expectItOpensInANewTab();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("opens in a new tab when pressing meta", function() {
|
|
||||||
clickEvent.metaKey = true;
|
|
||||||
expectItOpensInANewTab();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("opens in a new tab when pressing ctrl", function() {
|
|
||||||
clickEvent.ctrlKey = true;
|
|
||||||
expectItOpensInANewTab();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("opens in a new tab when middle clicking", function() {
|
|
||||||
clickEvent.which = 2;
|
|
||||||
expectItOpensInANewTab();
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it("tracks via AJAX if we're on the same site", function() {
|
|
||||||
// setup
|
|
||||||
clickEvent = generateClickEventOn('#same-site');
|
|
||||||
spyOn(Discourse, 'ajax');
|
|
||||||
spyOn(Discourse.URL, 'routeTo');
|
|
||||||
spyOn(Discourse.URL, 'origin').andReturn('http://discuss.domain.com');
|
|
||||||
// test
|
|
||||||
expect(track(clickEvent)).toBe(false);
|
|
||||||
expect(Discourse.ajax).toHaveBeenCalled();
|
|
||||||
expect(Discourse.URL.routeTo).toHaveBeenCalledWith('http://discuss.domain.com');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("tracks via custom URL", function() {
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
clickEvent = generateClickEventOn('a');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("in another window", function() {
|
|
||||||
// spies
|
|
||||||
spyOn(Discourse.User, 'current').andReturn(true);
|
|
||||||
spyOn(window, 'open').andCallFake(function() { return { focus: function() {} } });
|
|
||||||
spyOn(window, 'focus');
|
|
||||||
// test
|
|
||||||
expect(track(clickEvent)).toBe(false);
|
|
||||||
expect(window.open).toHaveBeenCalledWith('/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42', '_blank');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("in the same window", function() {
|
|
||||||
spyOn(Discourse.URL, 'redirectTo');
|
|
||||||
expect(track(clickEvent)).toBe(false);
|
|
||||||
expect(Discourse.URL.redirectTo).toHaveBeenCalledWith('/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42');
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,63 +0,0 @@
|
||||||
/*global waitsFor:true expect:true describe:true beforeEach:true it:true spyOn:true */
|
|
||||||
|
|
||||||
describe("Discourse.Utilities", function() {
|
|
||||||
|
|
||||||
describe("emailValid", function() {
|
|
||||||
|
|
||||||
it("allows upper case in first part of emails", function() {
|
|
||||||
expect(Discourse.Utilities.emailValid('Bob@example.com')).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("allows upper case in domain of emails", function() {
|
|
||||||
expect(Discourse.Utilities.emailValid('bob@EXAMPLE.com')).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("validateFilesForUpload", function() {
|
|
||||||
|
|
||||||
it("returns false when file is undefined", function() {
|
|
||||||
expect(Discourse.Utilities.validateFilesForUpload(null)).toBe(false);
|
|
||||||
expect(Discourse.Utilities.validateFilesForUpload(undefined)).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns false when file there is no file", function() {
|
|
||||||
expect(Discourse.Utilities.validateFilesForUpload([])).toBe(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("supports only one file", function() {
|
|
||||||
spyOn(bootbox, 'alert');
|
|
||||||
spyOn(Em.String, 'i18n');
|
|
||||||
expect(Discourse.Utilities.validateFilesForUpload([1, 2])).toBe(false);
|
|
||||||
expect(bootbox.alert).toHaveBeenCalled();
|
|
||||||
expect(Em.String.i18n).toHaveBeenCalledWith('post.errors.upload_too_many_images');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("supports only an image", function() {
|
|
||||||
var html = { type: "text/html" };
|
|
||||||
spyOn(bootbox, 'alert');
|
|
||||||
spyOn(Em.String, 'i18n');
|
|
||||||
expect(Discourse.Utilities.validateFilesForUpload([html])).toBe(false);
|
|
||||||
expect(bootbox.alert).toHaveBeenCalled();
|
|
||||||
expect(Em.String.i18n).toHaveBeenCalledWith('post.errors.only_images_are_supported');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("prevents the upload of a too large image", function() {
|
|
||||||
var image = { type: "image/png", size: 10 * 1024 };
|
|
||||||
Discourse.SiteSettings.max_upload_size_kb = 5;
|
|
||||||
spyOn(bootbox, 'alert');
|
|
||||||
spyOn(Em.String, 'i18n');
|
|
||||||
expect(Discourse.Utilities.validateFilesForUpload([image])).toBe(false);
|
|
||||||
expect(bootbox.alert).toHaveBeenCalled();
|
|
||||||
expect(Em.String.i18n).toHaveBeenCalledWith('post.errors.upload_too_large', { max_size_kb: 5 });
|
|
||||||
});
|
|
||||||
|
|
||||||
it("works", function() {
|
|
||||||
var image = { type: "image/png", size: 10 * 1024 };
|
|
||||||
Discourse.SiteSettings.max_upload_size_kb = 15;
|
|
||||||
expect(Discourse.Utilities.validateFilesForUpload([image])).toBe(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,21 +0,0 @@
|
||||||
// hacks for ember, this sets up our app for testing
|
|
||||||
|
|
||||||
(function(){
|
|
||||||
|
|
||||||
var currentWindowOnload = window.onload;
|
|
||||||
window.onload = function() {
|
|
||||||
if (currentWindowOnload) {
|
|
||||||
currentWindowOnload();
|
|
||||||
}
|
|
||||||
|
|
||||||
$('<div id="main"><div class="rootElement"></div></div>').appendTo($('body')).hide();
|
|
||||||
|
|
||||||
Discourse.SiteSettings = {}
|
|
||||||
|
|
||||||
Discourse.Router.map(function() {
|
|
||||||
this.route("jasmine",{path: "/jasmine"});
|
|
||||||
Discourse.routeBuilder.apply(this)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
})()
|
|
|
@ -1,98 +0,0 @@
|
||||||
/*global waitsFor:true expect:true describe:true beforeEach:true it:true */
|
|
||||||
|
|
||||||
describe("Discourse.Report", function() {
|
|
||||||
|
|
||||||
function dateString(days) {
|
|
||||||
return moment().subtract("days", days).format('YYYY-MM-DD');
|
|
||||||
}
|
|
||||||
|
|
||||||
function reportWithData(data) {
|
|
||||||
var arr = [];
|
|
||||||
_.each(data,function(val,index) {
|
|
||||||
arr.push({x: dateString(index), y: val});
|
|
||||||
});
|
|
||||||
return Discourse.Report.create({ type: 'topics', data: arr });
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("todayCount", function() {
|
|
||||||
it("returns the correct value", function() {
|
|
||||||
expect( reportWithData([5,4,3,2,1]).get('todayCount') ).toBe(5);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("yesterdayCount", function() {
|
|
||||||
it("returns the correct value", function() {
|
|
||||||
expect( reportWithData([5,4,3,2,1]).get('yesterdayCount') ).toBe(4);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("sumDays", function() {
|
|
||||||
it("adds the values for the given range of days, inclusive", function() {
|
|
||||||
expect( reportWithData([1,2,3,5,8,13]).sumDays(2,4) ).toBe(16);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("lastSevenDaysCount", function() {
|
|
||||||
it("returns the correct value", function() {
|
|
||||||
expect( reportWithData([100,9,8,7,6,5,4,3,200,300,400]).get('lastSevenDaysCount') ).toBe(42);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("percentChangeString", function() {
|
|
||||||
it("returns correct value when value increased", function() {
|
|
||||||
expect( reportWithData([]).percentChangeString(8,5) ).toBe("+60%");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns correct value when value decreased", function() {
|
|
||||||
expect( reportWithData([]).percentChangeString(2,8) ).toBe("-75%");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns 0 when value is unchanged", function() {
|
|
||||||
expect( reportWithData([]).percentChangeString(8,8) ).toBe("0%");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns Infinity when previous value was 0", function() {
|
|
||||||
expect( reportWithData([]).percentChangeString(8,0) ).toBe(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns -100 when yesterday's value was 0", function() {
|
|
||||||
expect( reportWithData([]).percentChangeString(0,8) ).toBe('-100%');
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns NaN when both yesterday and the previous day were both 0", function() {
|
|
||||||
expect( reportWithData([]).percentChangeString(0,0) ).toBe(null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("yesterdayCountTitle", function() {
|
|
||||||
it("displays percent change and previous value", function(){
|
|
||||||
var title = reportWithData([6,8,5,2,1]).get('yesterdayCountTitle')
|
|
||||||
expect( title.indexOf('+60%') ).not.toBe(-1);
|
|
||||||
expect( title ).toMatch("Was 5");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("handles when two days ago was 0", function() {
|
|
||||||
var title = reportWithData([6,8,0,2,1]).get('yesterdayCountTitle')
|
|
||||||
expect( title ).toMatch("Was 0");
|
|
||||||
expect( title ).not.toMatch("%");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("sevenDayCountTitle", function() {
|
|
||||||
it("displays percent change and previous value", function(){
|
|
||||||
var title = reportWithData([100,1,1,1,1,1,1,1,2,2,2,2,2,2,2,100,100]).get('sevenDayCountTitle');
|
|
||||||
expect( title ).toMatch("-50%");
|
|
||||||
expect( title ).toMatch("Was 14");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("thirtyDayCountTitle", function() {
|
|
||||||
it("displays percent change and previous value", function(){
|
|
||||||
var report = reportWithData([5,5,5,5]);
|
|
||||||
report.set('prev30Days', 10);
|
|
||||||
var title = report.get('thirtyDayCountTitle');
|
|
||||||
expect( title.indexOf('+50%') ).not.toBe(-1);
|
|
||||||
expect( title ).toMatch("Was 10");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*global waitsFor:true expect:true describe:true beforeEach:true it:true */
|
|
||||||
|
|
||||||
describe("Discourse.UserAction", function() {
|
|
||||||
|
|
||||||
describe("collapseStream", function() {
|
|
||||||
|
|
||||||
it("collapses all likes", function() {
|
|
||||||
var actions = [
|
|
||||||
Discourse.UserAction.create({
|
|
||||||
action_type: Discourse.UserAction.LIKE,
|
|
||||||
topic_id: 1,
|
|
||||||
user_id: 1,
|
|
||||||
post_number: 1
|
|
||||||
}), Discourse.UserAction.create({
|
|
||||||
action_type: Discourse.UserAction.EDIT,
|
|
||||||
topic_id: 2,
|
|
||||||
user_id: 1,
|
|
||||||
post_number: 1
|
|
||||||
}), Discourse.UserAction.create({
|
|
||||||
action_type: Discourse.UserAction.LIKE,
|
|
||||||
topic_id: 1,
|
|
||||||
user_id: 2,
|
|
||||||
post_number: 1
|
|
||||||
})
|
|
||||||
];
|
|
||||||
|
|
||||||
actions = Discourse.UserAction.collapseStream(actions);
|
|
||||||
|
|
||||||
expect(actions.length).toBe(2);
|
|
||||||
expect(actions[0].get("children").length).toBe(1);
|
|
||||||
expect(actions[0].get("children")[0].items.length).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,106 +0,0 @@
|
||||||
/*global waitsFor:true expect:true describe:true beforeEach:true it:true runs:true */
|
|
||||||
|
|
||||||
describe("PreloadStore", function() {
|
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
PreloadStore.store('bane', 'evil');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('get', function() {
|
|
||||||
|
|
||||||
it("returns undefined if the key doesn't exist", function() {
|
|
||||||
expect(PreloadStore.get('joker')).toBe(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns the value if the key exists", function() {
|
|
||||||
expect(PreloadStore.get('bane')).toBe('evil');
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('remove', function() {
|
|
||||||
|
|
||||||
it("removes the value if the key exists", function() {
|
|
||||||
PreloadStore.remove('bane');
|
|
||||||
expect(PreloadStore.get('bane')).toBe(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('getAndRemove', function() {
|
|
||||||
|
|
||||||
it("returns a promise that resolves to null", function() {
|
|
||||||
var done, storeResult;
|
|
||||||
done = storeResult = null;
|
|
||||||
PreloadStore.getAndRemove('joker').then(function(result) {
|
|
||||||
done = true;
|
|
||||||
storeResult = result;
|
|
||||||
});
|
|
||||||
waitsFor((function() { return done; }), "Promise never resolved", 1000);
|
|
||||||
runs(function() {
|
|
||||||
expect(storeResult).toBe(null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns a promise that resolves to the result of the finder", function() {
|
|
||||||
var done, finder, storeResult;
|
|
||||||
done = storeResult = null;
|
|
||||||
finder = function() { return 'evil'; };
|
|
||||||
PreloadStore.getAndRemove('joker', finder).then(function(result) {
|
|
||||||
done = true;
|
|
||||||
storeResult = result;
|
|
||||||
});
|
|
||||||
waitsFor((function() { return done; }), "Promise never resolved", 1000);
|
|
||||||
runs(function() {
|
|
||||||
expect(storeResult).toBe('evil');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns a promise that resolves to the result of the finder's promise", function() {
|
|
||||||
var done, finder, storeResult;
|
|
||||||
done = storeResult = null;
|
|
||||||
finder = function() {
|
|
||||||
return Ember.Deferred.promise(function(promise) { promise.resolve('evil'); });
|
|
||||||
};
|
|
||||||
PreloadStore.getAndRemove('joker', finder).then(function(result) {
|
|
||||||
done = true;
|
|
||||||
storeResult = result;
|
|
||||||
});
|
|
||||||
waitsFor((function() { return done; }), "Promise never resolved", 1000);
|
|
||||||
runs(function() {
|
|
||||||
expect(storeResult).toBe('evil');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns a promise that resolves to the result of the finder's rejected promise", function() {
|
|
||||||
var done, finder, storeResult;
|
|
||||||
done = storeResult = null;
|
|
||||||
finder = function() {
|
|
||||||
return Ember.Deferred.promise(function(promise) { promise.reject('evil'); });
|
|
||||||
};
|
|
||||||
PreloadStore.getAndRemove('joker', finder).then(null, function(rejectedResult) {
|
|
||||||
done = true;
|
|
||||||
storeResult = rejectedResult;
|
|
||||||
});
|
|
||||||
waitsFor((function() { return done; }), "Promise never rejected", 1000);
|
|
||||||
runs(function() {
|
|
||||||
expect(storeResult).toBe('evil');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it("returns a promise that resolves to 'evil'", function() {
|
|
||||||
var done, storeResult;
|
|
||||||
done = storeResult = null;
|
|
||||||
PreloadStore.getAndRemove('bane').then(function(result) {
|
|
||||||
done = true;
|
|
||||||
storeResult = result;
|
|
||||||
});
|
|
||||||
waitsFor((function() { return done; }), "Promise never resolved", 1000);
|
|
||||||
runs(function() {
|
|
||||||
expect(storeResult).toBe('evil');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,15 +0,0 @@
|
||||||
/*global waitsFor:true expect:true describe:true beforeEach:true it:true sanitizeHtml:true */
|
|
||||||
|
|
||||||
describe("sanitize", function(){
|
|
||||||
|
|
||||||
it("strips all script tags", function(){
|
|
||||||
var sanitized = sanitizeHtml("<div><script>alert('hi');</script></div>");
|
|
||||||
expect(sanitized).toBe("<div></div>");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("strips disallowed attributes", function(){
|
|
||||||
var sanitized = sanitizeHtml("<div><p class=\"funky\" wrong='1'>hello</p></div>");
|
|
||||||
expect(sanitized).toBe("<div><p class=\"funky\">hello</p></div>");
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
|
@ -1,3 +0,0 @@
|
||||||
/*
|
|
||||||
|
|
||||||
*/
|
|
|
@ -1,51 +0,0 @@
|
||||||
|
|
||||||
//= require env
|
|
||||||
|
|
||||||
//= require ../../app/assets/javascripts/preload_store.js
|
|
||||||
|
|
||||||
// probe framework first
|
|
||||||
//= require ../../app/assets/javascripts/discourse/components/probes.js
|
|
||||||
|
|
||||||
// Externals we need to load first
|
|
||||||
//= require ../../app/assets/javascripts/external/jquery-1.9.1.js
|
|
||||||
|
|
||||||
//= require ../../app/assets/javascripts/external/jquery.ui.widget.js
|
|
||||||
//= require ../../app/assets/javascripts/external/handlebars-1.0.rc.4.js
|
|
||||||
//= require ../../app/assets/javascripts/external_production/ember.js
|
|
||||||
//= require ../../app/assets/javascripts/external_production/group-helper.js
|
|
||||||
|
|
||||||
//= require ../../app/assets/javascripts/locales/i18n
|
|
||||||
//= require ../../app/assets/javascripts/locales/date_locales.js
|
|
||||||
//= require ../../app/assets/javascripts/discourse/helpers/i18n_helpers
|
|
||||||
//= require ../../app/assets/javascripts/locales/en
|
|
||||||
//
|
|
||||||
// Pagedown customizations
|
|
||||||
//= require ../../app/assets/javascripts/pagedown_custom.js
|
|
||||||
|
|
||||||
// The rest of the externals
|
|
||||||
//= require_tree ../../app/assets/javascripts/external
|
|
||||||
|
|
||||||
//= require ../../app/assets/javascripts/discourse
|
|
||||||
|
|
||||||
// Stuff we need to load first
|
|
||||||
//= require_tree ../../app/assets/javascripts/discourse/mixins
|
|
||||||
//= require ../../app/assets/javascripts/discourse/components/debounce
|
|
||||||
//= require ../../app/assets/javascripts/discourse/controllers/controller
|
|
||||||
//= require ../../app/assets/javascripts/discourse/views/modal/modal_body_view
|
|
||||||
//= require ../../app/assets/javascripts/discourse/models/model
|
|
||||||
//= require ../../app/assets/javascripts/discourse/routes/discourse_route
|
|
||||||
|
|
||||||
//= require_tree ../../app/assets/javascripts/discourse/controllers
|
|
||||||
//= require_tree ../../app/assets/javascripts/discourse/components
|
|
||||||
//= require_tree ../../app/assets/javascripts/discourse/models
|
|
||||||
//= require_tree ../../app/assets/javascripts/discourse/views
|
|
||||||
//= require_tree ../../app/assets/javascripts/discourse/helpers
|
|
||||||
//= require_tree ../../app/assets/javascripts/discourse/templates
|
|
||||||
//= require_tree ../../app/assets/javascripts/discourse/routes
|
|
||||||
//= require_tree ../../app/assets/javascripts/admin/models
|
|
||||||
|
|
||||||
//= require_tree ../../app/assets/javascripts/defer
|
|
||||||
|
|
||||||
//= require_tree .
|
|
||||||
|
|
||||||
//= require hacks
|
|
173
test/javascripts/components/click_track_test.js
Normal file
173
test/javascripts/components/click_track_test.js
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
/*global module:true test:true ok:true visit:true equal:true exists:true count:true equal:true present:true sinon:true blank:true */
|
||||||
|
|
||||||
|
module("Discourse.ClickTrack", {
|
||||||
|
setup: function() {
|
||||||
|
|
||||||
|
// Prevent any of these tests from navigating away
|
||||||
|
this.win = {focus: function() { } };
|
||||||
|
this.redirectTo = sinon.stub(Discourse.URL, "redirectTo");
|
||||||
|
sinon.stub(Discourse, "ajax");
|
||||||
|
this.windowOpen = sinon.stub(window, "open").returns(this.win);
|
||||||
|
sinon.stub(this.win, "focus");
|
||||||
|
|
||||||
|
$('#qunit-scratch').html([
|
||||||
|
'<div id="topic" id="1337">',
|
||||||
|
' <article data-post-id="42" data-user-id="3141">',
|
||||||
|
' <a href="http://www.google.com">google.com</a>',
|
||||||
|
' <a class="lightbox back quote-other-topic" href="http://www.google.com">google.com</a>',
|
||||||
|
' <a id="with-badge" data-user-id="314" href="http://www.google.com">google.com<span class="badge">1</span></a>',
|
||||||
|
' <a id="with-badge-but-not-mine" href="http://www.google.com">google.com<span class="badge">1</span></a>',
|
||||||
|
' <div class="onebox-result">',
|
||||||
|
' <a id="inside-onebox" href="http://www.google.com">google.com<span class="badge">1</span></a>',
|
||||||
|
' <a id="inside-onebox-forced" class="track-link" href="http://www.google.com">google.com<span class="badge">1</span></a>',
|
||||||
|
' </div>',
|
||||||
|
' <a id="same-site" href="http://discuss.domain.com">forum</a>',
|
||||||
|
' </article>',
|
||||||
|
'</div>'].join("\n"));
|
||||||
|
},
|
||||||
|
|
||||||
|
teardown: function() {
|
||||||
|
$('#topic').remove();
|
||||||
|
$('#qunit-scratch').html('');
|
||||||
|
|
||||||
|
Discourse.URL.redirectTo.restore();
|
||||||
|
Discourse.ajax.restore();
|
||||||
|
window.open.restore();
|
||||||
|
this.win.focus.restore();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var track = Discourse.ClickTrack.trackClick;
|
||||||
|
|
||||||
|
var generateClickEventOn = function(selector) {
|
||||||
|
return $.Event("click", { currentTarget: $(selector)[0] });
|
||||||
|
}
|
||||||
|
|
||||||
|
test("does not track clicks on lightboxes", function() {
|
||||||
|
var clickEvent = generateClickEventOn('.lightbox');
|
||||||
|
this.stub(clickEvent, "preventDefault");
|
||||||
|
ok(track(clickEvent));
|
||||||
|
ok(!clickEvent.preventDefault.calledOnce);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("it calls preventDefault when clicking on an a", function() {
|
||||||
|
var clickEvent = generateClickEventOn('a');
|
||||||
|
this.stub(clickEvent, "preventDefault");
|
||||||
|
track(clickEvent);
|
||||||
|
ok(clickEvent.preventDefault.calledOnce);
|
||||||
|
ok(Discourse.URL.redirectTo.calledOnce);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("does not track clicks on back buttons", function() {
|
||||||
|
ok(track(generateClickEventOn('.back')))
|
||||||
|
});
|
||||||
|
|
||||||
|
test("does not track clicks on quote buttons", function() {
|
||||||
|
ok(track(generateClickEventOn('.quote-other-topic')))
|
||||||
|
});
|
||||||
|
|
||||||
|
test("removes the href and put it as a data attribute", function() {
|
||||||
|
track(generateClickEventOn('a'));
|
||||||
|
|
||||||
|
var $link = $('a').first();
|
||||||
|
ok($link.hasClass('no-href'));
|
||||||
|
equal($link.data('href'), 'http://www.google.com');
|
||||||
|
blank($link.attr('href'));
|
||||||
|
ok($link.data('auto-route'));
|
||||||
|
ok(Discourse.URL.redirectTo.calledOnce);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var badgeClickCount = function(id, expected) {
|
||||||
|
track(generateClickEventOn('#' + id));
|
||||||
|
var $badge = $('span.badge', $('#' + id).first());
|
||||||
|
equal(parseInt($badge.html(), 10), expected);
|
||||||
|
};
|
||||||
|
|
||||||
|
test("does not update badge clicks on my own link", function() {
|
||||||
|
this.stub(Discourse.User, 'current').returns(314);
|
||||||
|
badgeClickCount('with-badge', 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("does not update badge clicks in my own post", function() {
|
||||||
|
this.stub(Discourse.User, 'current').returns(3141);
|
||||||
|
badgeClickCount('with-badge-but-not-mine', 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("updates badge counts correctly", function() {
|
||||||
|
badgeClickCount('inside-onebox', 1);
|
||||||
|
badgeClickCount('inside-onebox-forced', 2);
|
||||||
|
badgeClickCount('with-badge', 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
var trackRightClick = function() {
|
||||||
|
var clickEvent = generateClickEventOn('a')
|
||||||
|
clickEvent.which = 3;
|
||||||
|
return track(clickEvent);
|
||||||
|
};
|
||||||
|
|
||||||
|
test("right clicks change the href", function() {
|
||||||
|
ok(trackRightClick());
|
||||||
|
equal($('a').first().prop('href'), "http://www.google.com/");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("right clicks are tracked", function() {
|
||||||
|
Discourse.SiteSettings.track_external_right_clicks = true;
|
||||||
|
trackRightClick();
|
||||||
|
equal($('a').first().attr('href'), "/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42");
|
||||||
|
Discourse.SiteSettings.track_external_right_clicks = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var expectToOpenInANewTab = function(clickEvent) {
|
||||||
|
ok(!track(clickEvent));
|
||||||
|
ok(Discourse.ajax.calledOnce);
|
||||||
|
ok(window.open.calledOnce);
|
||||||
|
};
|
||||||
|
|
||||||
|
test("it opens in a new tab when pressing shift", function() {
|
||||||
|
var clickEvent = generateClickEventOn('a');
|
||||||
|
clickEvent.shiftKey = true;
|
||||||
|
expectToOpenInANewTab(clickEvent);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("it opens in a new tab when pressing meta", function() {
|
||||||
|
var clickEvent = generateClickEventOn('a');
|
||||||
|
clickEvent.metaKey = true;
|
||||||
|
expectToOpenInANewTab(clickEvent);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("it opens in a new tab when pressing meta", function() {
|
||||||
|
var clickEvent = generateClickEventOn('a');
|
||||||
|
clickEvent.ctrlKey = true;
|
||||||
|
expectToOpenInANewTab(clickEvent);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("it opens in a new tab when pressing meta", function() {
|
||||||
|
var clickEvent = generateClickEventOn('a');
|
||||||
|
clickEvent.which = 2;
|
||||||
|
expectToOpenInANewTab(clickEvent);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("tracks via AJAX if we're on the same site", function() {
|
||||||
|
this.stub(Discourse.URL, "routeTo");
|
||||||
|
this.stub(Discourse.URL, "origin").returns("http://discuss.domain.com");
|
||||||
|
|
||||||
|
ok(!track(generateClickEventOn('#same-site')));
|
||||||
|
ok(Discourse.ajax.calledOnce);
|
||||||
|
ok(Discourse.URL.routeTo.calledOnce);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test("tracks custom urls when opening in another window", function() {
|
||||||
|
var clickEvent = generateClickEventOn('a');
|
||||||
|
this.stub(Discourse.User, "current").returns(true);
|
||||||
|
ok(!track(clickEvent));
|
||||||
|
ok(this.windowOpen.calledWith('/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42', '_blank'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("tracks custom urls when opening in another window", function() {
|
||||||
|
var clickEvent = generateClickEventOn('a');
|
||||||
|
ok(!track(clickEvent));
|
||||||
|
ok(this.redirectTo.calledWith('/clicks/track?url=http%3A%2F%2Fwww.google.com&post_id=42'));
|
||||||
|
});
|
|
@ -1,4 +1,4 @@
|
||||||
/*global module:true test:true ok:true visit:true equal:true exists:true count:true equal:true present:true md5:true */
|
/*global module:true test:true ok:true visit:true equal:true exists:true count:true equal:true present:true md5:true sanitizeHtml:true */
|
||||||
|
|
||||||
module("Discourse.Markdown");
|
module("Discourse.Markdown");
|
||||||
|
|
||||||
|
@ -93,3 +93,9 @@ test("Oneboxing", function() {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("SanitizeHTML", function() {
|
||||||
|
|
||||||
|
equal(sanitizeHtml("<div><script>alert('hi');</script></div>"), "<div></div>");
|
||||||
|
equal(sanitizeHtml("<div><p class=\"funky\" wrong='1'>hello</p></div>"), "<div><p class=\"funky\">hello</p></div>");
|
||||||
|
|
||||||
|
});
|
73
test/javascripts/components/preload_store_test.js
Normal file
73
test/javascripts/components/preload_store_test.js
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
/*global module:true test:true ok:true visit:true expect:true exists:true equal:true count:true present:true asyncTest:true blank:true */
|
||||||
|
|
||||||
|
module("Discourse.PreloadStore", {
|
||||||
|
setup: function() {
|
||||||
|
PreloadStore.store('bane', 'evil');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("get", function() {
|
||||||
|
blank(PreloadStore.get('joker'), "returns blank for a missing key");
|
||||||
|
equal(PreloadStore.get('bane'), 'evil', "returns the value for that key");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("remove", function() {
|
||||||
|
PreloadStore.remove('bane');
|
||||||
|
blank(PreloadStore.get('bane'), "removes the value if the key exists");
|
||||||
|
});
|
||||||
|
|
||||||
|
asyncTest("getAndRemove returns a promise that resolves to null", function() {
|
||||||
|
expect(1);
|
||||||
|
|
||||||
|
PreloadStore.getAndRemove('joker').then(function(result) {
|
||||||
|
blank(result);
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
asyncTest("getAndRemove returns a promise that resolves to the result of the finder", function() {
|
||||||
|
expect(1);
|
||||||
|
|
||||||
|
var finder = function() { return 'batdance'; };
|
||||||
|
PreloadStore.getAndRemove('joker', finder).then(function(result) {
|
||||||
|
equal(result, 'batdance');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
asyncTest("getAndRemove returns a promise that resolves to the result of the finder's promise", function() {
|
||||||
|
expect(1);
|
||||||
|
|
||||||
|
var finder = function() {
|
||||||
|
return Ember.Deferred.promise(function(promise) { promise.resolve('hahahah'); });
|
||||||
|
};
|
||||||
|
|
||||||
|
PreloadStore.getAndRemove('joker', finder).then(function(result) {
|
||||||
|
equal(result, 'hahahah');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
asyncTest("returns a promise that rejects with the result of the finder's rejected promise", function() {
|
||||||
|
expect(1);
|
||||||
|
|
||||||
|
var finder = function() {
|
||||||
|
return Ember.Deferred.promise(function(promise) { promise.reject('error'); });
|
||||||
|
};
|
||||||
|
|
||||||
|
PreloadStore.getAndRemove('joker', finder).then(null, function(result) {
|
||||||
|
equal(result, 'error');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
asyncTest("returns a promise that resolves to 'evil'", function() {
|
||||||
|
expect(1);
|
||||||
|
|
||||||
|
PreloadStore.getAndRemove('bane').then(function(result) {
|
||||||
|
equal(result, 'evil');
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
});
|
52
test/javascripts/components/utilities_test.js
Normal file
52
test/javascripts/components/utilities_test.js
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/*global module:true test:true ok:true visit:true expect:true exists:true count:true equal:true */
|
||||||
|
|
||||||
|
module("Discourse.Utilities");
|
||||||
|
|
||||||
|
var utils = Discourse.Utilities;
|
||||||
|
|
||||||
|
test("emailValid", function() {
|
||||||
|
ok(utils.emailValid('Bob@example.com'), "allows upper case in the first part of emails");
|
||||||
|
ok(utils.emailValid('bob@EXAMPLE.com'), "allows upper case in the email domain");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var validUpload = utils.validateFilesForUpload;
|
||||||
|
|
||||||
|
test("validateFilesForUpload", function() {
|
||||||
|
ok(!validUpload(null), "no files are invalid");
|
||||||
|
ok(!validUpload(undefined), "undefined files are invalid");
|
||||||
|
ok(!validUpload([]), "empty array of files is invalid");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("uploading one file", function() {
|
||||||
|
this.stub(bootbox, "alert");
|
||||||
|
|
||||||
|
ok(!validUpload([1, 2]));
|
||||||
|
ok(bootbox.alert.calledOnce);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("ensures an image upload", function() {
|
||||||
|
var html = { type: "text/html" };
|
||||||
|
this.stub(bootbox, "alert");
|
||||||
|
|
||||||
|
ok(!validUpload([html]));
|
||||||
|
ok(bootbox.alert.calledOnce);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("prevents files that are too big from being uploaded", function() {
|
||||||
|
var image = { type: "image/png", size: 10 * 1024 };
|
||||||
|
Discourse.SiteSettings.max_upload_size_kb = 5;
|
||||||
|
this.stub(bootbox, "alert");
|
||||||
|
|
||||||
|
ok(!validUpload([image]));
|
||||||
|
ok(bootbox.alert.calledOnce);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("allows valid uploads to go through", function() {
|
||||||
|
var image = { type: "image/png", size: 10 * 1024 };
|
||||||
|
Discourse.SiteSettings.max_upload_size_kb = 15;
|
||||||
|
this.stub(bootbox, "alert");
|
||||||
|
|
||||||
|
ok(validUpload([image]));
|
||||||
|
ok(!bootbox.alert.calledOnce);
|
||||||
|
});
|
|
@ -13,6 +13,8 @@ module("Header", {
|
||||||
test("/", function() {
|
test("/", function() {
|
||||||
|
|
||||||
visit("/").then(function() {
|
visit("/").then(function() {
|
||||||
|
expect(2);
|
||||||
|
|
||||||
ok(exists("header"), "The header was rendered");
|
ok(exists("header"), "The header was rendered");
|
||||||
ok(exists("#site-logo"), "The logo was shown");
|
ok(exists("#site-logo"), "The logo was shown");
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,6 +13,8 @@ module("List Topics", {
|
||||||
test("/", function() {
|
test("/", function() {
|
||||||
|
|
||||||
visit("/").then(function() {
|
visit("/").then(function() {
|
||||||
|
expect(2);
|
||||||
|
|
||||||
ok(exists("#topic-list"), "The list of topics was rendered");
|
ok(exists("#topic-list"), "The list of topics was rendered");
|
||||||
ok(count('#topic-list .topic-list-item') > 0, "has topics");
|
ok(count('#topic-list .topic-list-item') > 0, "has topics");
|
||||||
});
|
});
|
||||||
|
|
60
test/javascripts/models/report_test.js
Normal file
60
test/javascripts/models/report_test.js
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*global module:true test:true ok:true visit:true expect:true exists:true count:true equal:true blank:true */
|
||||||
|
|
||||||
|
module("Discourse.Report");
|
||||||
|
|
||||||
|
function reportWithData(data) {
|
||||||
|
return Discourse.Report.create({
|
||||||
|
type: 'topics',
|
||||||
|
data: _.map(data, function(val, index) {
|
||||||
|
return {x: moment().subtract("days", index).format('YYYY-MM-DD'), y: val};
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
test("counts", function() {
|
||||||
|
var report = reportWithData([5, 4, 3, 2, 1, 100, 99, 98, 1000]);
|
||||||
|
|
||||||
|
equal(report.get('todayCount'), 5);
|
||||||
|
equal(report.get('yesterdayCount'), 4);
|
||||||
|
equal(report.sumDays(2, 4), 6, "adds the values for the given range of days, inclusive");
|
||||||
|
equal(report.get('lastSevenDaysCount'), 307, "sums 7 days excluding today");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("percentChangeString", function() {
|
||||||
|
var report = reportWithData([]);
|
||||||
|
|
||||||
|
equal(report.percentChangeString(8, 5), "+60%", "value increased");
|
||||||
|
equal(report.percentChangeString(2, 8), "-75%", "value decreased");
|
||||||
|
equal(report.percentChangeString(8, 8), "0%", "value unchanged");
|
||||||
|
blank(report.percentChangeString(8, 0), "returns blank when previous value was 0");
|
||||||
|
equal(report.percentChangeString(0, 8), "-100%", "yesterday was 0");
|
||||||
|
blank(report.percentChangeString(0, 0), "returns blank when both were 0");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("yesterdayCountTitle with valid values", function() {
|
||||||
|
var title = reportWithData([6,8,5,2,1]).get('yesterdayCountTitle');
|
||||||
|
ok(title.indexOf('+60%') !== -1);
|
||||||
|
ok(title.match(/Was 5/));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("yesterdayCountTitle when two days ago was 0", function() {
|
||||||
|
var title = reportWithData([6,8,0,2,1]).get('yesterdayCountTitle');
|
||||||
|
equal(title.indexOf('%'), -1);
|
||||||
|
ok(title.match(/Was 0/));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
test("sevenDayCountTitle", function() {
|
||||||
|
var title = reportWithData([100,1,1,1,1,1,1,1,2,2,2,2,2,2,2,100,100]).get('sevenDayCountTitle');
|
||||||
|
ok(title.match(/-50%/));
|
||||||
|
ok(title.match(/Was 14/));
|
||||||
|
});
|
||||||
|
|
||||||
|
test("thirtyDayCountTitle", function() {
|
||||||
|
var report = reportWithData([5,5,5,5]);
|
||||||
|
report.set('prev30Days', 10);
|
||||||
|
var title = report.get('thirtyDayCountTitle');
|
||||||
|
|
||||||
|
ok(title.indexOf('+50%') !== -1);
|
||||||
|
ok(title.match(/Was 10/));
|
||||||
|
});
|
29
test/javascripts/models/user_action_test.js
Normal file
29
test/javascripts/models/user_action_test.js
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*global module:true test:true ok:true visit:true expect:true exists:true count:true present:true equal:true */
|
||||||
|
|
||||||
|
module("Discourse.UserAction");
|
||||||
|
|
||||||
|
test("collapsing likes", function () {
|
||||||
|
var actions = Discourse.UserAction.collapseStream([
|
||||||
|
Discourse.UserAction.create({
|
||||||
|
action_type: Discourse.UserAction.LIKE,
|
||||||
|
topic_id: 1,
|
||||||
|
user_id: 1,
|
||||||
|
post_number: 1
|
||||||
|
}), Discourse.UserAction.create({
|
||||||
|
action_type: Discourse.UserAction.EDIT,
|
||||||
|
topic_id: 2,
|
||||||
|
user_id: 1,
|
||||||
|
post_number: 1
|
||||||
|
}), Discourse.UserAction.create({
|
||||||
|
action_type: Discourse.UserAction.LIKE,
|
||||||
|
topic_id: 1,
|
||||||
|
user_id: 2,
|
||||||
|
post_number: 1
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
|
||||||
|
equal(actions.length, 2);
|
||||||
|
|
||||||
|
equal(actions[0].get('children.length'), 1);
|
||||||
|
equal(actions[0].get('children')[0].items.length, 2);
|
||||||
|
});
|
|
@ -52,6 +52,7 @@ sinon.config = {
|
||||||
|
|
||||||
// Trick JSHint into allow document.write
|
// Trick JSHint into allow document.write
|
||||||
var d = document;
|
var d = document;
|
||||||
|
d.write('<div id="qunit-scratch" style="display:none"></div>');
|
||||||
d.write('<div id="ember-testing-container"><div id="ember-testing"></div></div>');
|
d.write('<div id="ember-testing-container"><div id="ember-testing"></div></div>');
|
||||||
d.write('<style>#ember-testing-container { position: absolute; background: white; bottom: 0; right: 0; width: 640px; height: 384px; overflow: auto; z-index: 9999; border: 1px solid #ccc; } #ember-testing { zoom: 50%; }</style>');
|
d.write('<style>#ember-testing-container { position: absolute; background: white; bottom: 0; right: 0; width: 640px; height: 384px; overflow: auto; z-index: 9999; border: 1px solid #ccc; } #ember-testing { zoom: 50%; }</style>');
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue