diff --git a/app/components/jobs-item.coffee b/app/components/jobs-item.coffee
new file mode 100644
index 00000000..ca085418
--- /dev/null
+++ b/app/components/jobs-item.coffee
@@ -0,0 +1,21 @@
+`import Ember from 'ember'`
+`import { colorForState } from 'travis/utils/helpers'`
+`import { languageConfigKeys } from 'travis/utils/keys-map';`
+
+JobsItemComponent = Ember.Component.extend
+ tagName: 'li'
+ classNameBindings: ['job.state']
+ classNames: ['tile', 'tile--jobs', 'row']
+
+ languages: (->
+ output = []
+
+ if config = @get('job.config')
+ for key, languageName of languageConfigKeys
+ if version = config[key]
+ output.push(languageName + ': ' + version)
+
+ output.join(' ')
+ ).property('job.config')
+
+`export default JobsItemComponent`
diff --git a/app/components/jobs-list.coffee b/app/components/jobs-list.coffee
new file mode 100644
index 00000000..65e26d5d
--- /dev/null
+++ b/app/components/jobs-list.coffee
@@ -0,0 +1,11 @@
+`import Ember from 'ember'`
+
+JobsListComponent = Ember.Component.extend
+ jobTableId: Ember.computed(->
+ if @get('required')
+ 'jobs'
+ else
+ 'allowed_failure_jobs'
+ )
+
+`export default JobsListComponent`
diff --git a/app/controllers/build.coffee b/app/controllers/build.coffee
index 1f86f62c..4e868705 100644
--- a/app/controllers/build.coffee
+++ b/app/controllers/build.coffee
@@ -12,6 +12,11 @@ Controller = Ember.Controller.extend GithubUrlPropertievs,
currentItemBinding: 'build'
+ jobsLoaded: (->
+ if jobs = @get('build.jobs')
+ jobs.everyBy('config')
+ ).property('build.jobs.@each.config')
+
loading: (->
@get('build.isLoading')
).property('build.isLoading')
diff --git a/app/templates/build.hbs b/app/templates/build.hbs
index cba093f5..bc4998ae 100644
--- a/app/templates/build.hbs
+++ b/app/templates/build.hbs
@@ -76,8 +76,14 @@
{{/unless}}
{{#if build.isMatrix}}
- {{view 'jobs' jobs=build.requiredJobs required="true"}}
- {{view 'jobs' jobs=build.allowedFailureJobs}}
+ {{#if jobsLoaded}}
+ {{jobs-list jobs=build.requiredJobs required="true"}}
+ {{jobs-list jobs=build.allowedFailureJobs}}
+ {{else}}
+
+
+
+ {{/if}}
{{else}}
{{view 'log' job=build.jobs.firstObject}}
{{/if}}
diff --git a/app/templates/components/jobs-item.hbs b/app/templates/components/jobs-item.hbs
new file mode 100644
index 00000000..e6ec8359
--- /dev/null
+++ b/app/templates/components/jobs-item.hbs
@@ -0,0 +1,46 @@
+{{#link-to "job" job.repo job}}
+
+
+
+
+
+
+ {{job.number}}
+
+
+
+
+
+
+ {{#if languages}}
+
+
+ {{languages}}
+
+ {{else}}
+
+
+ no language set
+
+ {{/if}}
+
+
+ {{#if job.config.env}}
+
+
+ {{job.config.env}}
+
+ {{else}}
+
+
+ no environment variables set
+
+ {{/if}}
+
+
+
+ {{format-duration job.duration}}
+
+
+
+{{/link-to}}
diff --git a/app/templates/components/jobs-list.hbs b/app/templates/components/jobs-list.hbs
new file mode 100644
index 00000000..ff8a0243
--- /dev/null
+++ b/app/templates/components/jobs-list.hbs
@@ -0,0 +1,21 @@
+{{#if jobs.length}}
+
+
+ {{#if required}}
+ Build Jobs
+ {{else}}
+ Allowed Failures
+
+
+
+ {{/if}}
+
+
+ {{#each job in jobs}}
+ {{jobs-item job=job}}
+ {{/each}}
+
+
+{{/if}}
diff --git a/app/templates/jobs.hbs b/app/templates/jobs.hbs
deleted file mode 100644
index 8c9fc3a2..00000000
--- a/app/templates/jobs.hbs
+++ /dev/null
@@ -1,85 +0,0 @@
-{{#if view.jobs.length}}
-
-
- {{#if view.required}}
- Build Jobs
- {{else}}
- Allowed Failures
-
-
-
- {{/if}}
-
- {{#each job in view.jobs}}
- {{#view 'jobs-item' context=job}}
-
- {{#if job.config}}
- {{#link-to "job" job.repo job}}
-
-
-
-
-
-
-
- {{#if job.id}}
- {{#if job.repo.slug}}
- {{number}}
- {{/if}}
- {{/if}}
-
-
-
-
- {{!-- {{config.os}} --}}
-
-
- {{#if view.languages}}
-
-
- {{view.languages}}
-
- {{else}}
-
-
- no language set
-
- {{/if}}
-
-
- {{#if config.env}}
-
-
- {{config.env}}
-
- {{else}}
-
-
- no environment variables set
-
- {{/if}}
-
-
-
- {{format-duration duration}}
-
-
-
-
- {{!--
-
- {{format-time finishedAt}}
-
--}}
-
- {{/link-to}}
- {{else}}
-
- {{/if}}
-
- {{/view}}
- {{!-- {{job.configKeys}} --}}
- {{/each}}
-
-{{/if}}
diff --git a/app/views/jobs-item.coffee b/app/views/jobs-item.coffee
deleted file mode 100644
index df04e841..00000000
--- a/app/views/jobs-item.coffee
+++ /dev/null
@@ -1,26 +0,0 @@
-`import BasicView from 'travis/views/basic'`
-`import { colorForState } from 'travis/utils/helpers'`
-`import { languageConfigKeys } from 'travis/utils/keys-map';`
-
-View = BasicView.extend
- tagName: 'div'
- classNameBindings: ['color']
- repoBinding: 'context.repo'
- jobBinding: 'context'
-
- color: (->
- colorForState(@get('job.state'))
- ).property('job.state')
-
- languages: (->
- output = []
-
- if config = @get('job.config')
- for key, languageName of languageConfigKeys
- if version = config[key]
- output.push(languageName + ': ' + version)
-
- output.join(' ')
- ).property()
-
-`export default View`
diff --git a/app/views/jobs.coffee b/app/views/jobs.coffee
deleted file mode 100644
index 241294f9..00000000
--- a/app/views/jobs.coffee
+++ /dev/null
@@ -1,23 +0,0 @@
-`import Ember from 'ember'`
-`import BasicView from 'travis/views/basic'`
-
-View = BasicView.extend
- templateName: 'jobs'
- buildBinding: 'controller.build'
-
- jobTableId: Ember.computed(->
- if @get('required')
- 'jobs'
- else
- 'allowed_failure_jobs'
- )
-
- actions:
- popupClose: ->
- @popupCloseAll()
-
- openHelpPopup: ->
- @popupCloseAll()
- @popup('help-allowed_failures')
-
-`export default View`
diff --git a/testem.json b/testem.json
index 23afdf07..7f180924 100644
--- a/testem.json
+++ b/testem.json
@@ -6,9 +6,6 @@
"SL_firefox"
],
"launch_in_dev": [
- "PhantomJS",
- "Chrome",
- "Firefox"
],
"launchers": {
"SL_chrome": {
diff --git a/tests/index.html b/tests/index.html
index 86513a02..8827643b 100644
--- a/tests/index.html
+++ b/tests/index.html
@@ -13,6 +13,15 @@
+
{{content-for 'head-footer'}}
{{content-for 'test-head-footer'}}
diff --git a/tests/unit/components/jobs-item-test.coffee b/tests/unit/components/jobs-item-test.coffee
new file mode 100644
index 00000000..31f0e9aa
--- /dev/null
+++ b/tests/unit/components/jobs-item-test.coffee
@@ -0,0 +1,39 @@
+`import { test, moduleForComponent } from 'ember-qunit'`
+
+moduleForComponent 'jobs-item', 'JobsItemComponent', {
+ # specify the other units that are required for this test
+ needs: ['helper:format-duration']
+}
+
+test 'it renders', ->
+ attributes = {
+ id: 10
+ state: 'passed'
+ number: '2'
+ config: {
+ rvm: '2.1.2'
+ jdk: 'openjdk6'
+ os: 'linux',
+ env: 'TESTS=unit'
+ },
+ duration: 100
+ }
+ job = Ember.Object.create(attributes)
+ component = @subject(job: job)
+ @append()
+
+ ok component.$().hasClass('passed'), 'component should have a state class (passed)'
+ equal component.$('.job-id').text().trim(), '2', 'job number should be displayed'
+ equal component.$('.job-lang').text().trim(), 'JDK: openjdk6 Ruby: 2.1.2', 'langauges list should be displayed'
+ equal component.$('.job-env').text().trim(), 'TESTS=unit', 'env should be displayed'
+ ok component.$('.job-os').hasClass('linux'), 'OS class should be added for OS icon'
+ equal component.$('.job-duration').text().trim(), '1 min 40 sec', 'duration should be displayed'
+
+test 'ouputs info on not set properties', ->
+ job = Ember.Object.create()
+
+ component = @subject(job: job)
+ @append()
+
+ ok component.$('.job-env').text().match(/no environment variables set/), 'a message for no env vars should be displayed'
+ ok component.$('.job-lang').text().match(/no language set/), 'a message about no language being set should be displayed'
diff --git a/tests/unit/components/jobs-list-test.coffee b/tests/unit/components/jobs-list-test.coffee
new file mode 100644
index 00000000..76a40abe
--- /dev/null
+++ b/tests/unit/components/jobs-list-test.coffee
@@ -0,0 +1,25 @@
+`import { test, moduleForComponent } from 'ember-qunit'`
+
+moduleForComponent 'jobs-list', 'JobsListComponent', {
+ needs: ['helper:format-duration', 'component:jobs-item']
+}
+
+test 'it renders a list of jobs', ->
+ jobs = [Ember.Object.create(id: 1, state: 'passed'),
+ Ember.Object.create(id: 1, state: 'failed')]
+
+ component = @subject(jobs: jobs, required: true)
+ @append()
+
+ equal component.$('.build-title').text().trim(), 'Build Jobs'
+ equal component.$('li').length, 2, 'there should be 2 job items'
+ ok component.$('li:nth(0)').hasClass('passed'), 'passed class should be applied to a job'
+ ok component.$('li:nth(1)').hasClass('failed'), 'failed class should be applied to a job'
+
+test 'it renders "Allowed Failures" version without a `required` property', ->
+ jobs = [Ember.Object.create(id: 1)]
+
+ component = @subject(jobs: jobs)
+ @append()
+
+ ok component.$('.build-title').text().match /Allowed Failures/
diff --git a/tests/unit/components/running-jobs-test.coffee b/tests/unit/components/running-jobs-test.coffee
new file mode 100644
index 00000000..a0fd1658
--- /dev/null
+++ b/tests/unit/components/running-jobs-test.coffee
@@ -0,0 +1,17 @@
+`import { test, moduleForComponent } from 'ember-qunit'`
+
+moduleForComponent 'running-jobs', 'RunningJobsComponent', {
+ # specify the other units that are required for this test
+ # needs: ['component:foo', 'helper:bar']
+}
+
+test 'it renders', ->
+ expect 2
+
+ # creates the component instance
+ component = @subject()
+ equal component._state, 'preRender'
+
+ # appends the component to the page
+ @append()
+ equal component._state, 'inDOM'