diff --git a/.gitignore b/.gitignore
index 3ed68716c..153e1e0ee 100644
--- a/.gitignore
+++ b/.gitignore
@@ -71,5 +71,7 @@ FLOOBITS_README.md
# mongodb
db/
+bin/node/
+bin/mongo/
-### If you add something here, copy it to the end of .npmignore, too. ###
\ No newline at end of file
+### If you add something here, copy it to the end of .npmignore, too. ###
diff --git a/.npmignore b/.npmignore
index aaef337fd..ae193b37d 100644
--- a/.npmignore
+++ b/.npmignore
@@ -86,6 +86,9 @@ dump.rdb
# Mongo
mongo/
+bin/node/
+bin/mongo/
+
# Karma coverage
-coverage/
\ No newline at end of file
+coverage/
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000..31cfaec28
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,13 @@
+nguage: node_js
+node_js:
+ - 0.10
+before_script:
+ - "npm install"
+ - export DISPLAY=:99.0
+ - sh -e /etc/init.d/xvfb start
+ - "./node_modules/.bin/bower install"
+ - "gem install sass"
+ - "./node_modules/.bin/brunch b"
+
+script:
+ - "./node_modules/.bin/karma start --browsers Firefox --single-run"
diff --git a/README.md b/README.md
index 676b2a65f..748a90d80 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,7 @@ CodeCombat
==========
![](https://dl.dropboxusercontent.com/u/138899/GitHub%20Wikis/readme_00.png)
+[![Build Status](https://travis-ci.org/codecombat/codecombat.png?branch=master)](https://travis-ci.org/codecombat/codecombat)
CodeCombat is a multiplayer programming game for learning how to code. **See the [Archmage developer wiki](https://github.com/codecombat/codecombat/wiki) for a dev setup guide, extensive documentation, and much more.**
diff --git a/app/locale/locale.coffee b/app/locale/locale.coffee
index 5d23c21bf..cb0a56ecd 100644
--- a/app/locale/locale.coffee
+++ b/app/locale/locale.coffee
@@ -49,3 +49,4 @@ module.exports =
uk: require './uk' # українська мова, Ukranian
hi: require './hi' # मानक हिन्दी, Hindi
ur: require './ur' # اُردُو, Urdu
+ 'ms-BA': require './ms-BA' # Bahasa Melayu, Bahasa Malaysia
diff --git a/app/locale/ms-BA.coffee b/app/locale/ms-BA.coffee
new file mode 100644
index 000000000..9d257b1c6
--- /dev/null
+++ b/app/locale/ms-BA.coffee
@@ -0,0 +1,43 @@
+module.exports = nativeDescription: "Bahasa Melayu", englishDescription: "Bahasa Malaysia", translation:
+
+ modal:
+ close: "Tutup"
+ okay: "Ok"
+
+ not_found:
+ page_not_found: "Halaman tidak ditemui"
+
+ nav:
+ # Header
+ sign_up: "Buat Akaun"
+ log_in: "Log Masuk"
+ log_out: "Log Keluar"
+ play: "bermain"
+ # Footer
+ home: "Halaman"
+ contribute: "Sumbangan"
+ legal: "Undang- undang"
+ about: "Tentang"
+ contact: "Hubungi"
+
+ forms:
+ name: "Nama"
+ email: "Emel"
+ message: "Mesej"
+ cancel: "Batal"
+
+ login:
+ log_in: "Log Masuk"
+ sign_up: "buat akaun baru"
+ or: ", atau "
+ recover: "perbaharui akaun"
+
+ signup:
+ description: "Ianya percuma. Hanya berberapa langkah sahaja:"
+ email_announcements: "Terima pengesahan melalui Emel"
+ coppa: "13+ atau bukan- USA"
+ coppa_why: "(Kenapa?)"
+ creating: "Membuat Akaun..."
+ sign_up: "Daftar"
+ or: "atau "
+ log_in: "log masuk"
diff --git a/app/locale/zh-HANS.coffee b/app/locale/zh-HANS.coffee
index 51f9905bc..46443e361 100644
--- a/app/locale/zh-HANS.coffee
+++ b/app/locale/zh-HANS.coffee
@@ -21,7 +21,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
admin: "超级管理员"
# Footer
home: "首页"
- contribute: ""
+ contribute: "贡献"
legal: "法律"
about: "关于"
contact: "联系我们"
@@ -162,15 +162,15 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
multiplayer_title: "多人游戏设置"
multiplayer_link_description: "把这个链接告诉小伙伴们,一起玩吧。"
multiplayer_hint_label: "提示:"
- multiplayer_hint: " 点击全选,然后按 ⌘-C 或 Ctrl-C 复制链接。"
+ multiplayer_hint: " 点击全选,然后按 Apple-C(苹果电脑)或 Ctrl-C 复制链接。"
multiplayer_coming_soon: "多人游戏的更多特性!"
guide_title: "指南"
- tome_minion_spells: "小助手的法术"
- tome_read_only_spells: "只读的法术"
+ tome_minion_spells: "助手的咒语"
+ tome_read_only_spells: "只读的咒语"
tome_other_units: "其他单元"
- tome_cast_button_castable: "投掷"
- tome_cast_button_casting: "投掷中"
- tome_cast_button_cast: "施法"
+ tome_cast_button_castable: "发动"
+ tome_cast_button_casting: "发动中"
+ tome_cast_button_cast: "发动咒语"
tome_autocast_delay: "自动施法延迟"
tome_autocast_1: "1 秒"
tome_autocast_3: "3 秒"
diff --git a/app/locale/zh-HANT.coffee b/app/locale/zh-HANT.coffee
index 2ecd0d978..1be29107a 100644
--- a/app/locale/zh-HANT.coffee
+++ b/app/locale/zh-HANT.coffee
@@ -2,182 +2,181 @@ module.exports = nativeDescription: "繁体中文", englishDescription: "Chinese
common:
loading: "Loading..."
-# modal:
-# close: "Close"
-# okay: "Okay"
-#
-# not_found:
-# page_not_found: "Page not found"
-#
-# nav:
-# # Header
-# sign_up: "Create Account"
-# log_in: "Log In"
-# log_out: "Log Out"
-# play: "Play"
-# editor: "Editor"
-# blog: "Blog"
-# forum: "Forum"
-# admin: "Admin"
-# # Footer
-# home: "Home"
-# contribute: "Contribute"
-# legal: "Legal"
-# about: "About"
-# contact: "Contact"
-# twitter_follow: "Follow"
-#
-# forms:
-# name: "Name"
-# email: "Email"
-# message: "Message"
-# cancel: "Cancel"
-#
-# login:
-# log_in: "Log In"
-# sign_up: "create new account"
-# or: ", or "
-# recover: "recover account"
-#
-# signup:
-# description: "It's free. Just need a couple things and you'll be good to go:"
-# email_announcements: "Receive announcements by email"
-# coppa: "13+ or non-USA"
-# coppa_why: "(Why?)"
-# creating: "Creating Account..."
-# sign_up: "Sign Up"
-# or: "or "
-# log_in: "log in with password"
-#
-# home:
-# slogan: "Learn to Code JavaScript by Playing a Game"
-# no_ie: "CodeCombat does not run in IE8 or older. Sorry!"
-# no_mobile: "CodeCombat wasn't designed for mobile devices and may not work!"
-# play: "Play"
-#
+ modal:
+ close: "關閉"
+ okay: "好"
+
+ not_found:
+ page_not_found: "找不到網頁"
+
+ nav:
+ # Header
+ sign_up: "註冊"
+ log_in: "登錄"
+ log_out: "退出"
+ play: "玩"
+ editor: "編輯"
+ blog: "博客"
+ forum: "論壇"
+ admin: "超級管理員"
+ # Footer
+ home: "首頁"
+ contribute: "貢獻"
+ legal: "法律"
+ about: "關於"
+ contact: "聯繫我們"
+ twitter_follow: "關注"
+
+ forms:
+ name: "名字"
+ email: "郵箱"
+ message: "留言"
+ cancel: "退出"
+
+ login:
+ log_in: "登錄"
+ sign_up: "註冊"
+ or: ",或"
+ recover: "找回帳戶"
+
+ signup:
+ description: "這是免費的。超簡單的喲:"
+ email_announcements: "通過郵件接收通知"
+# coppa: ""
+ coppa_why: "爲什麽?"
+ creating: "帳戶創建中..."
+ sign_up: "註冊"
+ or: "或"
+ log_in: "登錄"
+
+ home:
+ slogan: "通過玩遊戲學習Javascript 腳本語言"
+ no_ie: "抱歉!Internet Explorer 9 等舊的瀏覽器打不開此網站"
+ no_mobile: "CodeCombat 不是針對手機設備設計的,所以可能會出問題!"
+ play: "玩"
+
play:
- choose_your_level: "選擇你的水平"
-# adventurer_prefix: "You can jump to any level below, or discuss the levels on "
-# adventurer_forum: "the Adventurer forum"
-# adventurer_suffix: "."
-# campaign_beginner: "Beginner Campaign"
-# campaign_beginner_description: "... in which you learn the wizardry of programming."
-# campaign_dev: "Random Harder Levels"
-# campaign_dev_description: "... in which you learn the interface while doing something a little harder."
-# campaign_multiplayer: "Multiplayer Arenas"
-# campaign_multiplayer_description: "... in which you code head-to-head against other players."
-# campaign_player_created: "Player-Created"
-# campaign_player_created_description: "... in which you battle against the creativity of your fellow Artisan Wizards."
-# level_difficulty: "Difficulty: "
-#
-# contact:
-# contact_us: "Contact CodeCombat"
-# welcome: "Good to hear from you! Use this form to send us email."
-# contribute_prefix: "If you're interested in contributing, check out our "
-# contribute_page: "contribute page"
-# contribute_suffix: "!"
-# forum_prefix: "For anything public, please try "
-# forum_page: "our forum"
-# forum_suffix: " instead."
-# sending: "Sending..."
-# send: "Send Feedback"
-#
+ choose_your_level: "選取難度"
+ adventurer_prefix: "你可以選擇以下任意關卡,或者討論以上的關卡 "
+ adventurer_forum: "冒險家論壇"
+ adventurer_suffix: "."
+ campaign_beginner: "新手作戰"
+ campaign_beginner_description: "...在這裡可以學到編程技巧。"
+ campaign_dev: "隨機關卡"
+ campaign_dev_description: "...在這裡你可以學到做一些複雜功能的接口。"
+ campaign_multiplayer: "多人競技場"
+ campaign_multiplayer_description: "...在這裡你可以和其他玩家們進行代碼近戰。"
+ campaign_player_created: "已創建的玩家"
+ campaign_player_created_description: "...在這裡你可以與你的小夥伴的創造力戰鬥 技術指導."
+ level_difficulty: "難度"
+
+ contact:
+ contact_us: "聯繫我們"
+ welcome: "很高興收到你的信!用這個表格給我們發電郵。 "
+ contribute_prefix: "如果你想貢獻代碼,請看 "
+ contribute_page: "貢獻代碼頁面"
+ contribute_suffix: "!"
+ forum_prefix: "對於任何公共部份,放手去做吧 "
+ forum_page: "我們的論壇"
+ forum_suffix: "代替。"
+ sending: "發送中。。。"
+ send: "意見反饋"
+
diplomat_suggestion:
-# title: "Help translate CodeCombat!"
-# sub_heading: "We need your language skills."
- pitch_body: "We develop CodeCombat in English, but we already have players all over the world. Many of them want to play in Chinese (Traditional) but don't speak English, so if you can speak both, please consider signing up to be a Diplomat and help translate both the CodeCombat website and all the levels into Chinese (Traditional)."
- missing_translations: "Until we can translate everything into Chinese (Traditional), you'll see English when Chinese (Traditional) isn't available."
-# learn_more: "Learn more about being a Diplomat"
-# subscribe_as_diplomat: "Subscribe as a Diplomat"
-#
-# account_settings:
-# title: "Account Settings"
-# not_logged_in: "Log in or create an account to change your settings."
-# autosave: "Changes Save Automatically"
-# me_tab: "Me"
-# picture_tab: "Picture"
-# wizard_tab: "Wizard"
-# password_tab: "Password"
-# emails_tab: "Emails"
-# language_tab: "Language"
-# gravatar_select: "Select which Gravatar photo to use"
-# gravatar_add_photos: "Add thumbnails and photos to a Gravatar account for your email to choose an image."
-# gravatar_add_more_photos: "Add more photos to your Gravatar account to access them here."
-# wizard_color: "Wizard Clothes Color"
-# new_password: "New Password"
-# new_password_verify: "Verify"
-# email_subscriptions: "Email Subscriptions"
-# email_announcements: "Announcements"
-# email_announcements_description: "Get emails on the latest news and developments at CodeCombat."
-# contributor_emails: "Contributor Class Emails"
-# contribute_prefix: "We're looking for people to join our party! Check out the "
-# contribute_page: "contribute page"
-# contribute_suffix: " to find out more."
-# email_toggle: "Toggle All"
-# language: "Language"
-# saving: "Saving..."
-# error_saving: "Error Saving"
-# saved: "Changes Saved"
-# password_mismatch: "Password does not match."
-#
-# account_profile:
-# edit_settings: "Edit Settings"
-# profile_for_prefix: "Profile for "
-# profile_for_suffix: ""
-# profile: "Profile"
-# user_not_found: "No user found. Check the URL?"
-# gravatar_not_found_mine: "We couldn't find your profile associated with:"
-# gravatar_signup_prefix: "Sign up at "
-# gravatar_signup_suffix: " to get set up!"
-# gravatar_not_found_other: "Alas, there's no profile associated with this person's email address."
-# gravatar_contact: "Contact"
-# gravatar_websites: "Websites"
-# gravatar_accounts: "As Seen On"
-# gravatar_profile_link: "Full Gravatar Profile"
-#
-# play_level:
-# level_load_error: "Level could not be loaded."
-# done: "Done"
-# grid: "Grid"
-# customize_wizard: "Customize Wizard"
-# home: "Home"
-# guide: "Guide"
-# multiplayer: "Multiplayer"
-# restart: "Restart"
-# goals: "Goals"
-# action_timeline: "Action Timeline"
-# click_to_select: "Click on a unit to select it."
-# reload_title: "Reload All Code?"
-# reload_really: "Are you sure you want to reload this level back to the beginning?"
-# reload_confirm: "Reload All"
-# victory_title_prefix: ""
-# victory_title_suffix: " Complete"
-# victory_sign_up: "Sign Up for Updates"
-# victory_sign_up_poke: "Want to get the latest news by email? Create a free account and we'll keep you posted!"
-# victory_rate_the_level: "Rate the level: "
-# victory_play_next_level: "Play Next Level"
-# victory_go_home: "Go Home"
-# victory_review: "Tell us more!"
-# victory_hour_of_code_done: "Are You Done?"
-# victory_hour_of_code_done_yes: "Yes, I'm finished with my Hour of Code!"
-# multiplayer_title: "Multiplayer Settings"
-# multiplayer_link_description: "Give this link to anyone to have them join you."
-# multiplayer_hint_label: "Hint:"
-# multiplayer_hint: " Click the link to select all, then press Apple-C or Ctrl-C to copy the link."
-# multiplayer_coming_soon: "More multiplayer features to come!"
-# guide_title: "Guide"
-# tome_minion_spells: "Your Minions' Spells"
-# tome_read_only_spells: "Read-Only Spells"
-# tome_other_units: "Other Units"
-# tome_cast_button_castable: "Cast"
-# tome_cast_button_casting: "Casting"
-# tome_cast_button_cast: "Spell Cast"
-# tome_autocast_delay: "Autocast Delay"
-# tome_autocast_1: "1 second"
-# tome_autocast_3: "3 seconds"
-# tome_autocast_5: "5 seconds"
-# tome_autocast_manual: "Manual"
-# tome_select_spell: "Select a Spell"
-# tome_select_a_thang: "Select Someone for "
-# tome_available_spells: "Available Spells"
-# hud_continue: "Continue (press shift-space)"
+ title: "幫我們翻譯CodeCombat"
+ sub_heading: "我們需要您的語言技能"
+ pitch_body: "我們開發了CodeCombat的英文版,但是現在我們的玩家遍佈全球。很多人想玩中文(繁体)版的,卻不會說英文,所以如果你中英文都會,請考慮一下參加我們的翻譯工作,幫忙把 CodeCombat 網站還有所有的關卡翻譯成中文(繁体)。"
+# missing_translations: ""
+# learn_more: ""
+# subscribe_as_diplomat: ""
+
+ account_settings:
+ title: "帳戶設置"
+ not_logged_in: "登錄或創建一個帳戶來修改設置。"
+ autosave: "自動保存修改"
+ me_tab: "我"
+ picture_tab: "圖片"
+ wizard_tab: "巫師"
+ password_tab: "密碼"
+ emails_tab: "郵件"
+ gravatar_select: "選擇使用 Gravatar 照片"
+ gravatar_add_photos: "添加小圖和照片到一个 Gravatar 帳戶供你選擇。"
+ gravatar_add_more_photos: "添加更多照片到你的 Gravatar 帳戶并查看。"
+ wizard_color: "巫師 衣服 顏色"
+ new_password: "新密碼"
+ new_password_verify: "核實"
+ email_subscriptions: "郵箱驗證"
+ email_announcements: "通知"
+ email_announcements_description: "接收關於 CodeCombat 最近的新聞和發展的郵件。"
+# contributor_emails: ""
+ contribute_prefix: "我們在尋找志同道合的人!請到 "
+ contribute_page: "貢獻頁面"
+ contribute_suffix: " 查看更多信息。"
+ email_toggle: "切換所有"
+ saving: "保存中..."
+ error_saving: "保存時出錯"
+ saved: "保存修改"
+ password_mismatch: "密碼不匹配。"
+
+ account_profile:
+ edit_settings: "編輯設置"
+ profile_for_prefix: "關於TA的基本資料:"
+ profile_for_suffix: ""
+ profile: "基本資料"
+ user_not_found: "沒有找到用戶。檢查URL?"
+ gravatar_not_found_mine: "我們找不到TA的基本資料:"
+ gravatar_not_found_email_suffix: "."
+ gravatar_signup_prefix: "去註冊 "
+ gravatar_signup_suffix: " 去設置!"
+ gravatar_not_found_other: "哎呦,沒有與這個人的郵箱相關的資料。"
+ gravatar_contact: "聯繫"
+ gravatar_websites: "網站"
+# gravatar_accounts: ""
+ gravatar_profile_link: "完善 Gravatar 資料"
+
+ play_level:
+ level_load_error: "關卡不能載入。"
+ done: "完成"
+ grid: "格子"
+ customize_wizard: "自定義巫師"
+ home: "主頁"
+ guide: "指南"
+ multiplayer: "多人遊戲"
+ restart: "重新開始"
+ goals: "目標"
+ action_timeline: "行動時間軸"
+ click_to_select: "點擊選擇一個單元。"
+ reload_title: "重載所有代碼?"
+ reload_really: "確定重載這一關,返回開始處?"
+ reload_confirm: "重載所有"
+ victory_title_prefix: ""
+ victory_title_suffix: " 完成"
+ victory_sign_up: "保存進度"
+ victory_sign_up_poke: "想保存你的代碼?創建一個免費帳戶吧!"
+ victory_rate_the_level: "評估關卡: "
+ victory_play_next_level: "下一關"
+ victory_go_home: "返回主頁"
+ victory_review: "給我們反饋!"
+ victory_hour_of_code_done: "你完成了嗎?"
+ victory_hour_of_code_done_yes: "是的,我完成了我的代碼!"
+ multiplayer_title: "多人遊戲設置"
+ multiplayer_link_description: "把這個鏈接告訴小夥伴們,一起玩吧。"
+ multiplayer_hint_label: "提示:"
+ multiplayer_hint: " 點擊全選,然後按 Apple-C(苹果電腦)或 Ctrl-C 複製鏈接。"
+ multiplayer_coming_soon: "多人遊戲的更多特性!"
+ guide_title: "指南"
+ tome_minion_spells: "助手的咒語"
+ tome_read_only_spells: "只讀的咒語"
+ tome_other_units: "其他單元"
+ tome_cast_button_castable: "發動"
+ tome_cast_button_casting: "發動中"
+ tome_cast_button_cast: "咒語"
+ tome_autocast_delay: "自動施法延遲"
+ tome_autocast_1: "1 秒"
+ tome_autocast_3: "3 秒"
+ tome_autocast_5: "5 秒"
+ tome_autocast_manual: "手動手动"
+ tome_select_spell: "選擇一個法術"
+ tome_select_a_thang: "選擇人物來 "
+ tome_available_spells: "可用的法術"
+ hud_continue: "繼續 (按 shift-空格)"
diff --git a/app/templates/editor/level/save.jade b/app/templates/editor/level/save.jade
index 572119c60..7bff18551 100644
--- a/app/templates/editor/level/save.jade
+++ b/app/templates/editor/level/save.jade
@@ -1,9 +1,6 @@
extends /templates/modal/save_version
-block modal-header-content
- h3(data-i18n="editor.save_view_title") Save New Version
-
-block content
+block modal-body-content
h3= "Level: " + level.get('name') + " - " + (levelNeedsSave ? "Modified" : "Not Modified")
if levelNeedsSave
form#save-level-form.form-horizontal
diff --git a/app/templates/modal/contact.jade b/app/templates/modal/contact.jade
index 0ad90cff8..83c47528c 100644
--- a/app/templates/modal/contact.jade
+++ b/app/templates/modal/contact.jade
@@ -1,11 +1,9 @@
-block modal-header-content
- h3(data-i18n="contact.contact_modal_title") Contact
+extends /templates/modal/modal_base
-.modal-header
- .button.close(type="button", data-dismiss="modal", aria-hidden="true") ×
+block modal-header-content
h3(data-i18n="contact.contact_us") Contact CodeCombat...
-.modal-body
+block modal-body-content
p
span(data-i18n="contact.welcome") Good to hear from you! Use this form to send us email.
span(data-i18n="contact.contribute_prefix") If you're interested in contributing, check out our
@@ -25,7 +23,7 @@ block modal-header-content
.controls
textarea#contact-message.input-block-level(name="message", rows=8)
-.modal-footer
+block modal-footer-content
span.sending-indicator.pull-left.hide(data-i18n="contact.sending") Sending...
a(href='#', data-dismiss="modal", aria-hidden="true", data-i18n="forms.cancel").btn Cancel
button.btn.btn-primary#contact-submit-button(data-i18n="contact.send") Send Feedback
diff --git a/app/templates/modal/save_version.jade b/app/templates/modal/save_version.jade
index 3fc07059c..14c29b20b 100644
--- a/app/templates/modal/save_version.jade
+++ b/app/templates/modal/save_version.jade
@@ -1,6 +1,9 @@
-.modal-header
+extends /templates/modal/modal_base
+
+block modal-header-content
h3(data-i18n="save.save_version_title") Save New Version
-.modal-body
+
+block modal-body-content
form.form-horizontal
.control-group
label.control-label(for="commitMessage") Commit Message
@@ -11,7 +14,11 @@
.controls
input#major-version.input-large(name="version-is-major", type="checkbox")
span.help-block
-.modal-footer
+
+block modal-body-wait-content
+ h3 Saving...
+
+block modal-footer-content
#accept-cla-wrapper.alert.alert-info
| To save changes, first you must agree to
strong#cla-link our CLA
@@ -20,7 +27,3 @@
button.btn(data-dismiss="modal") Cancel
button.btn.btn-primary#save-version-button Save
-.modal-body.wait.hide
- h3 Saving...
- .progress.progress-striped.active
- .bar
diff --git a/app/views/modal/contact_modal.coffee b/app/views/modal/contact_modal.coffee
index f71e93d0f..dd3f0c40e 100644
--- a/app/views/modal/contact_modal.coffee
+++ b/app/views/modal/contact_modal.coffee
@@ -22,6 +22,7 @@ contactSchema =
module.exports = class ContactView extends View
id: "contact-modal"
template: template
+ closeButton: true
events:
"click #contact-submit-button": "contact"
diff --git a/karma.conf.js b/karma.conf.js
index 7b8df7609..4e7e335e4 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -1,83 +1,83 @@
// Testacular configuration
// Generated on Fri Feb 15 2013 18:38:33 GMT-0500 (EST)
+module.exports = function(config) {
-// base path, that will be used to resolve files and exclude
-basePath = '.';
+ config.set({
+ // base path, that will be used to resolve files and exclude
+ basePath : '',
+
+ frameworks: ['jasmine'],
+
+ // list of files / patterns to load in the browser
+ files : [
+ 'public/javascripts/vendor.js',
+ 'public/lib/ace/ace.js',
+ 'public/javascripts/app.js',
+
+ 'test/app/**/*.coffee'
+ ],
+
+ preprocessors : {
+ '**/*.coffee': 'coffee',
+ '**/javascripts/app.js': 'coverage'
+ },
+
+ // list of files to exclude
+ exclude : [],
+
+ // test results reporter to use
+ // possible values: 'dots', 'progress', 'junit'
+ reporters : ['progress', 'coverage'],
+
+ // web server port
+ port : 9050,
+
+ // cli runner port
+ runnerPort : 9051,
+
+ // enable / disable colors in the output (reporters and logs)
+ colors : true,
+
+ // level of logging
+ // possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
+ logLevel : config.LOG_INFO,
+
+ // enable / disable watching file and executing tests whenever any file changes
+ autoWatch : true,
+
+ // Start these browsers, currently available:
+ // - Chrome
+ // - ChromeCanary
+ // - Firefox
+ // - Opera
+ // - Safari (only Mac)
+ // - PhantomJS
+ // - IE (only Windows)
+ browsers : ['Chrome'],
-// list of files / patterns to load in the browser
-files = [
- JASMINE,
- JASMINE_ADAPTER,
-
- 'public/javascripts/vendor.js',
- 'public/lib/ace/ace.js',
- 'public/javascripts/app.js',
-
- 'test/app/**/*.coffee'
-];
+ // If browser does not capture in given timeout [ms], kill it
+ captureTimeout : 5000,
-// list of files to exclude
-exclude = [
-
-];
+ // Continuous Integration mode
+ // if true, it capture browsers, run tests and executing
+ singleRun : false,
+ coverageReporter : {
+ type : 'html',
+ dir : 'coverage/'
+ },
-// test results reporter to use
-// possible values: 'dots', 'progress', 'junit'
-reporters = ['progress', 'coverage'];
-//reporters = ['progress'];
+ plugins : [
+ 'karma-jasmine',
+ 'karma-chrome-launcher',
+ 'karma-phantomjs-launcher',
+ 'karma-coffee-preprocessor',
+ 'karma-coverage',
+ 'karma-firefox-launcher'
+ ]
+ });
-
-// web server port
-port = 9050;
-
-
-// cli runner port
-runnerPort = 9051;
-
-
-// enable / disable colors in the output (reporters and logs)
-colors = true;
-
-
-// level of logging
-// possible values: LOG_DISABLE || LOG_ERROR || LOG_WARN || LOG_INFO || LOG_DEBUG
-logLevel = LOG_INFO;
-
-
-// enable / disable watching file and executing tests whenever any file changes
-autoWatch = true;
-
-
-// Start these browsers, currently available:
-// - Chrome
-// - ChromeCanary
-// - Firefox
-// - Opera
-// - Safari (only Mac)
-// - PhantomJS
-// - IE (only Windows)
-browsers = ['Chrome'];
-
-
-// If browser does not capture in given timeout [ms], kill it
-captureTimeout = 5000;
-
-
-// Continuous Integration mode
-// if true, it capture browsers, run tests and exit
-singleRun = false;
-
-
-preprocessors = {
- '**/*.coffee': 'coffee',
- '**/javascripts/app.js': 'coverage'
-};
-
-coverageReporter = {
- type : 'html',
- dir : 'coverage/'
};
diff --git a/package.json b/package.json
index de10103b4..f65e5145d 100644
--- a/package.json
+++ b/package.json
@@ -26,7 +26,7 @@
],
"scripts": {
"start": "node ./index.js",
- "test": "brunch test",
+ "test": "./node_modules/.bin/karma start",
"predeploy": "echo Starting deployment--hold onto your butts.; echo Skipping brunch build --production",
"postdeploy": "echo Deployed. Unclench."
},
@@ -72,13 +72,23 @@
"clean-css-brunch": "> 1.0 < 1.8",
"auto-reload-brunch": "> 1.0 < 1.8",
"brunch": "~1.7.4",
- "karma": "~0.8.0",
"jasmine-node": "",
"nodemon": "0.7.5",
"marked": "0.2.x",
"telepath-brunch": "https://github.com/nwinter/telepath-brunch/tarball/master",
"bower": "~1.2.8",
- "bless-brunch": "~1.6.1"
+ "bless-brunch": "~1.6.1",
+ "karma-script-launcher": "~0.1.0",
+ "karma-chrome-launcher": "~0.1.2",
+ "karma-firefox-launcher": "~0.1.3",
+ "karma-html2js-preprocessor": "~0.1.0",
+ "karma-coffee-preprocessor": "~0.1.2",
+ "karma-jasmine": "~0.1.5",
+ "requirejs": "~2.1.10",
+ "karma-requirejs": "~0.2.1",
+ "karma-phantomjs-launcher": "~0.1.1",
+ "karma": "~0.10.9",
+ "karma-coverage": "~0.1.4"
},
"license": "Copyright © 2014 CodeCombat",
"private": true,
diff --git a/scripts/devSetup/node.py b/scripts/devSetup/node.py
index 3503d362d..a788d0a69 100644
--- a/scripts/devSetup/node.py
+++ b/scripts/devSetup/node.py
@@ -55,6 +55,7 @@ class Node(Dependency):
wants_to_upgrade = strtobool(user_input)
except:
print u"Please enter y or n. "
+ user_input = raw_input()
continue
break
if wants_to_upgrade:
diff --git a/test/server/handlers/level_component.spec.coffee b/test/server/handlers/level_component.spec.coffee
index d88b62142..e80315fcf 100644
--- a/test/server/handlers/level_component.spec.coffee
+++ b/test/server/handlers/level_component.spec.coffee
@@ -7,30 +7,120 @@ describe 'LevelComponent', ->
description:'Makes the unit uncontrollably bash anything bashable, using the bash system.'
code: 'bash();'
language: 'javascript'
- official: true
permissions:simplePermissions
components = {}
url = getURL('/db/level.component')
- it 'clears things first', (done) ->
+ it 'preparing test : clears things first.', (done) ->
clearModels [Level, LevelComponent], (err) ->
expect(err).toBeNull()
done()
- it 'can make a LevelComponent, without setting official.', (done) ->
+ it 'can\'t be created by ordinary users.', (done) ->
loginJoe (joe) ->
+ request.post {uri:url, json:component}, (err, res, body) ->
+ expect(res.statusCode).toBe(403)
+ done()
+
+ it 'can be created by an admin.', (done) ->
+ loginAdmin (joe) ->
request.post {uri:url, json:component}, (err, res, body) ->
expect(res.statusCode).toBe(200)
- expect(body.official).toBeUndefined()
+ expect(body._id).toBeDefined()
+ expect(body.name).toBe(component.name)
+ expect(body.description).toBe(component.description)
+ expect(body.code).toBe(component.code)
+ expect(body.language).toBe(component.language)
+ expect(body.__v).toBe(0)
+ expect(body.creator).toBeDefined()
+ expect(body.original).toBeDefined()
+ expect(body.created).toBeDefined()
+ expect(body.version).toBeDefined()
+ expect(body.permissions).toBeDefined()
components[0] = body
done()
- it 'can allows admins to edit the official property.', (done) ->
+ it 'have a unique name.', (done) ->
+ loginAdmin (joe) ->
+ request.post {uri:url, json:component}, (err, res, body) ->
+ expect(res.statusCode).toBe(422)
+ done()
+
+ it 'can read by an admin.', (done) ->
+ loginAdmin (joe) ->
+ request.get {uri:url+'/'+components[0]._id}, (err, res, body) ->
+ expect(res.statusCode).toBe(200)
+ body = JSON.parse(body)
+ expect(body._id).toBe(components[0]._id)
+ done()
+
+ it 'can be read by ordinary users.', (done) ->
+ loginJoe (joe) ->
+ request.get {uri:url+'/'+components[0]._id}, (err, res, body) ->
+ expect(res.statusCode).toBe(200)
+ body = JSON.parse(body)
+ expect(body._id).toBe(components[0]._id)
+ expect(body.name).toBe(components[0].name)
+ expect(body.slug).toBeDefined()
+ expect(body.description).toBe(components[0].description)
+ expect(body.code).toBe(components[0].code)
+ expect(body.language).toBe(components[0].language)
+ expect(body.__v).toBe(0)
+ expect(body.official).toBeDefined()
+ expect(body.creator).toBeDefined()
+ expect(body.original).toBeDefined()
+ expect(body.created).toBeDefined()
+ expect(body.configSchema).toBeDefined()
+ expect(body.dependencies).toBeDefined()
+ expect(body.propertyDocumentation).toBeDefined()
+ expect(body.version.isLatestMajor).toBe(true)
+ expect(body.version.isLatestMinor).toBe(true)
+ expect(body.permissions).toBeDefined()
+ done()
+
+ it 'is unofficial by default', (done) ->
+ loginJoe (joe) ->
+ request.get {uri:url+'/'+components[0]._id}, (err, res, body) ->
+ expect(res.statusCode).toBe(200)
+ body = JSON.parse(body)
+ expect(body._id).toBe(components[0]._id)
+ expect(body.official).toBe(false)
+ done()
+
+ it 'has system ai by default', (done) ->
+ loginJoe (joe) ->
+ request.get {uri:url+'/'+components[0]._id}, (err, res, body) ->
+ expect(res.statusCode).toBe(200)
+ body = JSON.parse(body)
+ expect(body._id).toBe(components[0]._id)
+ expect(body.system).toBe("ai")
+ done()
+
+ it 'official property isn\'t editable by an ordinary user.', (done) ->
+ components[0].official = true
+ loginJoe (joe) ->
+ request.post {uri:url, json:components[0]}, (err, res, body) ->
+ expect(res.statusCode).toBe(403)
+ done()
+
+ it 'official property is editable by an admin.', (done) ->
components[0].official = true
loginAdmin (joe) ->
request.post {uri:url, json:components[0]}, (err, res, body) ->
- expect(body.official).toBe(true)
expect(res.statusCode).toBe(200)
- done()
+ expect(body.official).toBe(true)
+ expect(body.original).toBe(components[0].original)
+ expect(body.version.isLatestMinor).toBe(true)
+ expect(body.version.isLatestMajor).toBe(true)
+ components[1] = body
+
+ request.get {uri:url+'/'+components[0]._id}, (err, res, body) ->
+ expect(res.statusCode).toBe(200)
+ body = JSON.parse(body)
+ expect(body._id).toBe(components[0]._id)
+ expect(body.official).toBe(false)
+ expect(body.version.isLatestMinor).toBe(false)
+ expect(body.version.isLatestMajor).toBe(false)
+ done()
\ No newline at end of file