diff --git a/.editorconfig b/.editorconfig
index 219985c2..12b0275a 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -13,8 +13,5 @@ insert_final_newline = true
indent_style = space
indent_size = 2
-[*.hbs]
-insert_final_newline = false
-
[*.{diff,md}]
trim_trailing_whitespace = false
diff --git a/app/components/build-result-summary-table.hbs b/app/components/build-result-summary-table.hbs
new file mode 100644
index 00000000..3e75e092
--- /dev/null
+++ b/app/components/build-result-summary-table.hbs
@@ -0,0 +1,13 @@
+
+
+
+ | Scenario |
+ Result |
+
+
+
+ {{#each this.scenarios as |scenario|}}
+
+ {{/each}}
+
+
diff --git a/app/components/build-result-summary-table.js b/app/components/build-result-summary-table.js
new file mode 100644
index 00000000..34b4371d
--- /dev/null
+++ b/app/components/build-result-summary-table.js
@@ -0,0 +1,11 @@
+import classic from 'ember-classic-decorator';
+import { tagName } from '@ember-decorators/component';
+import { readOnly } from '@ember/object/computed';
+import Component from '@ember/component';
+
+@classic
+@tagName('')
+export default class BuildResultSummaryTable extends Component {
+ @readOnly('results.scenarios')
+ scenarios;
+}
diff --git a/app/components/build-result-summary-table/row.hbs b/app/components/build-result-summary-table/row.hbs
new file mode 100644
index 00000000..53ad92fe
--- /dev/null
+++ b/app/components/build-result-summary-table/row.hbs
@@ -0,0 +1,13 @@
+
+ | {{@scenario.scenarioName}} |
+
+ {{#if @scenario.passed}}
+ Passed
+ {{else}}
+ Failed
+ {{#if @scenario.allowedToFail}}
+ (allowed)
+ {{/if}}
+ {{/if}}
+ |
+
diff --git a/app/components/build-result-summary-table/row.js b/app/components/build-result-summary-table/row.js
new file mode 100644
index 00000000..d8de185e
--- /dev/null
+++ b/app/components/build-result-summary-table/row.js
@@ -0,0 +1,13 @@
+import Component from '@glimmer/component';
+
+export default class BuildResultSummaryTableRow extends Component {
+ get testResultClass() {
+ if (this.args.scenario.passed) {
+ return 'passed';
+ }
+ if (this.args.scenario.allowedToFail) {
+ return 'allowed-failure';
+ }
+ return 'failed';
+ }
+}
diff --git a/app/models/test-result.js b/app/models/test-result.js
index bcc3b42a..021045d0 100644
--- a/app/models/test-result.js
+++ b/app/models/test-result.js
@@ -25,6 +25,9 @@ export default class TestResult extends Model {
@attr('string')
semverString;
+ @attr()
+ emberTryResults;
+
@belongsTo('version')
version;
diff --git a/app/styles/_canary_test_results.scss b/app/styles/_canary_test_results.scss
index 6e8bb75f..09ebe7ac 100644
--- a/app/styles/_canary_test_results.scss
+++ b/app/styles/_canary_test_results.scss
@@ -26,7 +26,7 @@
background-color: #e61313;
}
- &.error {
+ &.error, &.allowed-failure {
background-color: #9e9e9e;
}
}
diff --git a/app/styles/app.scss b/app/styles/app.scss
index 712d80be..bdf4afa5 100644
--- a/app/styles/app.scss
+++ b/app/styles/app.scss
@@ -15,6 +15,7 @@
@import "addons_index";
@import "addons-list";
@import "components/build-result-output";
+@import "components/build-result-summary-table";
@import "components/code-search";
@import "components/dependency-table";
@import "components/large-search";
diff --git a/app/styles/components/_build-result-summary-table.scss b/app/styles/components/_build-result-summary-table.scss
new file mode 100644
index 00000000..f581c3c8
--- /dev/null
+++ b/app/styles/components/_build-result-summary-table.scss
@@ -0,0 +1,14 @@
+.build-result-summary-table {
+ width: auto;
+
+ td {
+ padding: 0.75em;
+ }
+
+ th:first-child {
+ width: 15em;
+ }
+ th:not(:first-child) {
+ width: 8em;
+ }
+}
diff --git a/app/templates/admin/build-results/show.hbs b/app/templates/admin/build-results/show.hbs
index 91c51a59..366d1482 100644
--- a/app/templates/admin/build-results/show.hbs
+++ b/app/templates/admin/build-results/show.hbs
@@ -23,6 +23,11 @@
+ {{#if this.buildResult.emberTryResults}}
+ Results
+
+ {{/if}}
+
Output
diff --git a/tests/acceptance/build-results-test.js b/tests/acceptance/build-results-test.js
index e8910852..80735a5e 100644
--- a/tests/acceptance/build-results-test.js
+++ b/tests/acceptance/build-results-test.js
@@ -2,6 +2,7 @@ import { findAll, click, currentURL, currentRouteName, visit } from '@ember/test
import { module, test } from 'qunit';
import { percySnapshot } from 'ember-percy';
import { setupEmberObserverTest } from '../helpers/setup-ember-observer-test';
+import emberTryScenario from 'ember-observer/tests/helpers/ember-try-scenario';
import findByText from '../helpers/find-by-text';
import login from 'ember-observer/tests/helpers/login';
import moment from 'moment';
@@ -9,234 +10,264 @@ import moment from 'moment';
module('Acceptance | build results', function(hooks) {
setupEmberObserverTest(hooks);
- test('displays basic info about a build', async function(assert) {
- let addon = server.create('addon');
- let addonVersion = server.create('version', { addonId: addon.id });
- server.create('testResult', {
- versionId: addonVersion.id,
- createdAt: moment('2016-08-07 16:30').utc()
+ module('Index', function() {
+ test('displays basic info about a build', async function(assert) {
+ let addon = server.create('addon');
+ let addonVersion = server.create('version', { addon });
+ server.create('testResult', {
+ version: addonVersion,
+ createdAt: moment('2016-08-07 16:30').utc()
+ });
+
+ await login();
+ await visit('/admin/build-results');
+
+ assert.equal(currentRouteName(), 'admin.build-results.index');
+ let results = findAll('.test-build-result td');
+ assert.dom(results[0]).hasText(addon.name, 'displays addon name');
+ assert.dom(results[1]).hasText('1.0.0', 'displays addon version');
+ assert.dom(results[2]).hasText('2016-08-07 16:30', 'displays date/time');
});
- await login();
- await visit('/admin/build-results');
-
- assert.equal(currentRouteName(), 'admin.build-results.index');
- let results = findAll('.test-build-result td');
- assert.dom(results[0]).hasText(addon.name, 'displays addon name');
- assert.dom(results[1]).hasText('1.0.0', 'displays addon version');
- assert.dom(results[2]).hasText('2016-08-07 16:30', 'displays date/time');
- });
-
- test('sorts results by run date', async function(assert) {
- let addon = server.create('addon');
- let addonVersion = server.create('version', { addonId: addon.id });
- let middleTestResult = server.create('testResult', {
- createdAt: moment('2016-11-19 12:00:00').utc()
- });
- let earliestTestResult = server.create('testResult', {
- createdAt: moment('2016-11-19 00:00:01').utc()
- });
- let latestTestResult = server.create('testResult', {
- createdAt: moment('2016-11-19 23:59:59').utc()
+ test('sorts results by run date', async function(assert) {
+ let addon = server.create('addon');
+ let addonVersion = server.create('version', { addon });
+ let middleTestResult = server.create('testResult', {
+ version: addonVersion,
+ createdAt: moment('2016-11-19 12:00:00').utc()
+ });
+ let earliestTestResult = server.create('testResult', {
+ version: addonVersion,
+ createdAt: moment('2016-11-19 00:00:01').utc()
+ });
+ let latestTestResult = server.create('testResult', {
+ version: addonVersion,
+ createdAt: moment('2016-11-19 23:59:59').utc()
+ });
+
+ await login();
+ await visit('/admin/build-results');
+
+ assert.dom('.test-build-result').hasAttribute('data-testResultId', `${latestTestResult.id}`);
+
+ let results = findAll('.test-build-result');
+ assert.dom(results[1]).hasAttribute('data-testResultId', `${middleTestResult.id}`);
+ assert.dom(results[2]).hasAttribute('data-testResultId', `${earliestTestResult.id}`);
});
- addonVersion.update({
- testResultIds: [middleTestResult.id, earliestTestResult.id, latestTestResult.id]
+
+ test('displays appropriate status based on result', async function(assert) {
+ let addon = server.create('addon');
+ let addonVersion = server.create('version', { addon });
+ server.create('testResult', {
+ version: addonVersion,
+ succeeded: false,
+ statusMessage: 'timed out',
+ createdAt: moment().subtract(30, 'minutes').utc()
+ });
+ server.create('testResult', {
+ version: addonVersion,
+ succeeded: true,
+ createdAt: moment().subtract(1, 'hour').utc()
+ });
+
+ await login();
+ await visit('/admin/build-results');
+
+ let results = findAll('.test-build-result');
+ assert.dom(results[0]).containsText('failed - timed out', 'displays failure notice with status message for failed builds');
+ assert.dom(results[1]).containsText('succeeded', 'displays "succeeded" for successful builds');
});
- await login();
- await visit('/admin/build-results');
+ test('displays semver string for non-canary builds', async function(assert) {
+ let addon = server.create('addon');
+ let addonVersion = server.create('version', { addon });
+ server.create('testResult', {
+ version: addonVersion,
+ canary: false,
+ semverString: '>= 2.0.0',
+ createdAt: moment('2016-08-07 16:30').utc()
+ });
- assert.dom('.test-build-result').hasAttribute('data-testResultId', `${latestTestResult.id}`);
+ await login();
+ await visit('/admin/build-results');
- let results = findAll('.test-build-result');
- assert.dom(results[1]).hasAttribute('data-testResultId', `${middleTestResult.id}`);
- assert.dom(results[2]).hasAttribute('data-testResultId', `${earliestTestResult.id}`);
- });
+ assert.dom('.test-build-result').containsText('>= 2.0.0', 'displays semver string');
- test('displays appropriate status based on result', async function(assert) {
- let addon = server.create('addon');
- let addonVersion = server.create('version', { addonId: addon.id });
- let timedOutResult = server.create('testResult', {
- succeeded: false,
- statusMessage: 'timed out',
- createdAt: moment().subtract(30, 'minutes').utc()
- });
- let succeededResult = server.create('testResult', {
- succeeded: true,
- createdAt: moment().subtract(1, 'hour').utc()
- });
- addonVersion.update({
- testResultIds: [timedOutResult.id, succeededResult.id]
+ await click(findByText('.test-build-result a', 'details'));
+
+ assert.dom('.test-semver-string').hasText('>= 2.0.0', 'displays semver string');
});
- await login();
- await visit('/admin/build-results');
+ test('displays appropriate indication for canary builds', async function(assert) {
+ let addon = server.create('addon');
+ let addonVersion = server.create('version', { addon });
+ server.create('testResult', {
+ version: addonVersion,
+ canary: true,
+ createdAt: moment('2016-08-07 16:30').utc()
+ });
- let results = findAll('.test-build-result');
- assert.dom(results[0]).containsText('failed - timed out', 'displays failure notice with status message for failed builds');
- assert.dom(results[1]).containsText('succeeded', 'displays "succeeded" for successful builds');
- });
+ await login();
+ await visit('/admin/build-results');
+
+ assert.dom('.test-build-result').containsText('canary', 'displays indication for canary builds on list');
- test('displays semver string for non-canary builds', async function(assert) {
- let addon = server.create('addon');
- let addonVersion = server.create('version', { addonId: addon.id });
- server.create('testResult', {
- versionId: addonVersion.id,
- canary: false,
- semverString: '>= 2.0.0',
- createdAt: moment('2016-08-07 16:30').utc()
+ await click(findByText('.test-build-result a', 'details'));
+ assert.dom('.test-semver-string').hasText('canary', 'displays indication for canary builds in detail');
});
- await login();
- await visit('/admin/build-results');
+ test('links to previous day', async function(assert) {
+ await login();
+ await visit('/admin/build-results?date=2017-02-01');
- assert.dom('.test-build-result').containsText('>= 2.0.0', 'displays semver string');
+ assert.dom('a[href="/admin/build-results?date=2017-01-31"]').exists('has a link to the results for the previous day');
+ });
- await click(findByText('.test-build-result a', 'details'));
+ test('links to following day if not viewing the current date', async function(assert) {
+ await login();
+ await visit('/admin/build-results?date=2016-11-18');
- assert.dom('.test-semver-string').hasText('>= 2.0.0', 'displays semver string');
- });
-
- test('displays appropriate indication for canary builds', async function(assert) {
- let addon = server.create('addon');
- let addonVersion = server.create('version', { addonId: addon.id });
- server.create('testResult', {
- versionId: addonVersion.id,
- canary: true,
- createdAt: moment('2016-08-07 16:30').utc()
+ assert.dom('a[href="/admin/build-results?date=2016-11-19"]').exists('has a link to the results for the following day');
});
- await login();
- await visit('/admin/build-results');
+ test('does not link to following day if viewing the current date', async function(assert) {
+ let tomorrow = moment().add(1, 'day').utc().format('Y-M-D');
- assert.dom('.test-build-result').containsText('canary', 'displays indication for canary builds on list');
+ await login();
+ await visit('/admin/build-results');
- await click(findByText('.test-build-result a', 'details'));
- assert.dom('.test-semver-string').hasText('canary', 'displays indication for canary builds in detail');
- });
+ assert.dom(`a[href="/admin/build-results?date=${tomorrow}"]`).doesNotExist('does not have a link to the results for the following day');
+ });
- test('links to previous day', async function(assert) {
- await login();
- await visit('/admin/build-results?date=2017-02-01');
+ test('links to detail for individual builds', async function(assert) {
+ let version = server.create('version');
+ let testResult = server.create('testResult', { version });
- assert.dom('a[href="/admin/build-results?date=2017-01-31"]').exists('has a link to the results for the previous day');
- });
+ await login();
+ await visit('/admin/build-results');
+ await click(findByText('.test-build-result a', 'details'));
- test('links to following day if not viewing the current date', async function(assert) {
- await login();
- await visit('/admin/build-results?date=2016-11-18');
+ await percySnapshot('/admin/build-results');
- assert.dom('a[href="/admin/build-results?date=2016-11-19"]').exists('has a link to the results for the following day');
+ assert.equal(currentURL(), `/admin/build-results/${testResult.id}`);
+ });
});
- test('does not link to following day if viewing the current date', async function(assert) {
- let tomorrow = moment().add(1, 'day').utc().format('Y-M-D');
+ module('Individual build detail', function() {
+ test('detail page shows data for a build', async function(assert) {
+ let addon = server.create('addon');
+ let version = server.create('version', {
+ addon
+ });
+ let testResult = server.create('testResult', {
+ version,
+ output: 'this is the output',
+ createdAt: moment('2016-08-01 12:34:56').utc()
+ });
+
+ await login();
+ await visit(`/admin/build-results/${testResult.id}`);
+
+ assert.dom('.test-addon-name').hasText(addon.name, 'displays addon name');
+ assert.dom('.test-addon-version').hasText(version.version, 'displays addon version');
+ assert.dom('.test-run-date').hasText('2016-08-01 12:34', 'displays date/time tests ran');
+ assert.dom('.test-output').hasText('this is the output', "displays result's output");
+ });
- await login();
- await visit('/admin/build-results');
+ test('detail page shows "succeeded" for status when build succeeded', async function(assert) {
+ let version = server.create('version');
+ let testResult = server.create('testResult', {
+ version,
+ succeeded: true
+ });
- assert.dom(`a[href="/admin/build-results?date=${tomorrow}"]`).doesNotExist('does not have a link to the results for the following day');
- });
+ await login();
+ await visit(`/admin/build-results/${testResult.id}`);
- test('links to detail for individual builds', async function(assert) {
- let version = server.create('version');
- let testResult = server.create('testResult', { versionId: version.id });
+ assert.dom('.test-build-status').hasText('succeeded', 'displays "succeeded" for build status');
+ });
- await login();
- await visit('/admin/build-results');
- await click(findByText('.test-build-result a', 'details'));
+ test('detail page shows status message when build did not succeeded', async function(assert) {
+ let version = server.create('version');
+ let testResult = server.create('testResult', {
+ version,
+ succeeded: false,
+ statusMessage: 'this is the status'
+ });
- await percySnapshot('/admin/build-results');
+ await login();
+ await visit(`/admin/build-results/${testResult.id}`);
- assert.equal(currentURL(), `/admin/build-results/${testResult.id}`);
- });
-
- test('detail page shows data for a build', async function(assert) {
- let addon = server.create('addon');
- let version = server.create('version', {
- addonId: addon.id
- });
- let testResult = server.create('testResult', {
- versionId: version.id,
- output: 'this is the output',
- createdAt: moment('2016-08-01 12:34:56').utc()
+ assert.dom('.test-build-status').hasText('this is the status', 'displays status message for the build');
});
- server.db.versions.update(version, { testResultId: testResult.id });
- await login();
- await visit(`/admin/build-results/${testResult.id}`);
+ test('detail page has a "retry" button for failed builds', async function(assert) {
+ assert.expect(3);
- assert.dom('.test-addon-name').hasText(addon.name, 'displays addon name');
- assert.dom('.test-addon-version').hasText(version.version, 'displays addon version');
- assert.dom('.test-run-date').hasText('2016-08-01 12:34', 'displays date/time tests ran');
- assert.dom('.test-output').hasText('this is the output', "displays result's output");
- });
+ let version = server.create('version');
+ let testResult = server.create('testResult', {
+ version,
+ succeeded: false,
+ statusMessage: 'failed'
+ });
- test('detail page shows "succeeded" for status when build succeeded', async function(assert) {
- let version = server.create('version');
- let testResult = server.create('testResult', {
- versionId: version.id,
- succeeded: true
- });
- server.db.versions.update(version, { testResultId: testResult.id });
+ server.post('/test_results/:id/retry', function() {
+ assert.ok(true, 'makes retry request');
+ });
- await login();
- await visit(`/admin/build-results/${testResult.id}`);
+ await login();
+ await visit(`/admin/build-results/${testResult.id}`);
- assert.dom('.test-build-status').hasText('succeeded', 'displays "succeeded" for build status');
- });
+ assert.dom('.test-retry-build').exists('"retry" button exists');
+
+ await click('.test-retry-build');
- test('detail page shows status message when build did not succeeded', async function(assert) {
- let version = server.create('version');
- let testResult = server.create('testResult', {
- versionId: version.id,
- succeeded: false,
- statusMessage: 'this is the status'
+ assert.dom('.test-retry-build').doesNotExist('"retry" button removed after retrying');
});
- server.db.versions.update(version, { testResultId: testResult.id });
- await login();
- await visit(`/admin/build-results/${testResult.id}`);
+ test('detail page does not have a "retry" button for successful builds', async function(assert) {
+ let version = server.create('version');
+ let testResult = server.create('testResult', {
+ version,
+ succeeded: true
+ });
- assert.dom('.test-build-status').hasText('this is the status', 'displays status message for the build');
- });
+ await login();
+ await visit(`/admin/build-results/${testResult.id}`);
- test('detail page has a "retry" button for failed builds', async function(assert) {
- assert.expect(3);
-
- let version = server.create('version');
- let testResult = server.create('testResult', {
- versionId: version.id,
- succeeded: false,
- statusMessage: 'failed'
+ assert.dom('.test-retry-build').doesNotExist('no "retry" button should be displayed');
});
- server.db.versions.update(version, { testResultId: testResult.id });
- server.post('/test_results/:id/retry', function() {
- assert.ok(true, 'makes retry request');
+ test('when test result has ember-try results, displays a summary table', async function(assert) {
+ let testResult = server.create('testResult', {
+ version: server.create('version'),
+ succeeded: true,
+ emberTryResults: {
+ scenarios: [
+ emberTryScenario('3.4'),
+ emberTryScenario('3.8'),
+ emberTryScenario('3.12'),
+ emberTryScenario('3.13')
+ ]
+ }
+ });
+
+ await login();
+ await visit(`/admin/build-results/${testResult.id}`);
+
+ assert.dom('[data-test-results-table]').exists();
});
- await login();
- await visit(`/admin/build-results/${testResult.id}`);
-
- assert.dom('.test-retry-build').exists('"retry" button exists');
+ test('when test result does not have ember-try results, does not display summary table', async function(assert) {
+ let testResult = server.create('testResult', {
+ version: server.create('version'),
+ succeeded: true,
+ emberTryResults: null
+ });
- await click('.test-retry-build');
+ await visit(`/admin/build-results/${testResult.id}`);
- assert.dom('.test-retry-build').doesNotExist('"retry" button removed after retrying');
- });
-
- test('detail page does not have a "retry" button for successful builds', async function(assert) {
- let version = server.create('version');
- let testResult = server.create('testResult', {
- versionId: version.id,
- succeeded: true
+ assert.dom('[data-test-results-table]').doesNotExist();
});
- server.db.versions.update(version, { testResultId: testResult.id });
-
- await login();
- await visit(`/admin/build-results/${testResult.id}`);
-
- assert.dom('.test-retry-build').doesNotExist('no "retry" button should be displayed');
});
});
diff --git a/tests/helpers/ember-try-scenario.js b/tests/helpers/ember-try-scenario.js
new file mode 100644
index 00000000..56fdaf63
--- /dev/null
+++ b/tests/helpers/ember-try-scenario.js
@@ -0,0 +1,15 @@
+export default function emberTryScenario(version) {
+ return {
+ scenarioName: `ember-${version}`,
+ passed: true,
+ allowedToFail: false,
+ dependencies: [
+ {
+ name: 'ember-source',
+ versionSeen: `${version}.2`,
+ versionExpected: `${version}.0`,
+ type: 'yarn'
+ }
+ ]
+ };
+}
diff --git a/tests/integration/components/build-result-summary-table-test.js b/tests/integration/components/build-result-summary-table-test.js
new file mode 100644
index 00000000..eed381e1
--- /dev/null
+++ b/tests/integration/components/build-result-summary-table-test.js
@@ -0,0 +1,60 @@
+import { module, test } from 'qunit';
+import { setupRenderingTest } from 'ember-qunit';
+import { render } from '@ember/test-helpers';
+import hbs from 'htmlbars-inline-precompile';
+
+import emberTryScenario from 'ember-observer/tests/helpers/ember-try-scenario';
+
+module('Integration | Component | build-result-summary-table', function(hooks) {
+ setupRenderingTest(hooks);
+
+ test('displays a row for each scenario in the provided results', async function(assert) {
+ this.emberTryResults = {
+ scenarios: [
+ emberTryScenario('3.4'),
+ emberTryScenario('3.8'),
+ emberTryScenario('3.12'),
+ emberTryScenario('3.13'),
+ ]
+ };
+
+ await render(hbs`
+
+ `);
+
+ assert.dom('table tbody tr').exists({ count: 4 });
+ });
+
+ test('displays information for a scenario', async function(assert) {
+ let scenario = emberTryScenario('3.13');
+ this.emberTryResults = {
+ scenarios: [
+ scenario
+ ]
+ };
+
+ await render(hbs`
+
+ `);
+
+ assert.dom('tbody tr td:nth-child(1)').hasText(scenario.scenarioName, 'displays scenario name in first column');
+ assert.dom('tbody tr td:nth-child(2)').hasText('Passed', 'displays result in second column');
+ });
+
+ test('when an allowed-to-fail scenario fails, result text reflects that', async function(assert) {
+ let scenario = emberTryScenario('3.13');
+ scenario.allowedToFail = true;
+ scenario.passed = false;
+ this.emberTryResults = {
+ scenarios: [
+ scenario
+ ]
+ };
+
+ await render(hbs`
+
+ `);
+
+ assert.dom('tbody tr td:nth-child(2)').hasText('Failed (allowed)');
+ });
+});