Merge pull request #473 from travis-ci/acceptance-tests

Acceptance tests
This commit is contained in:
Piotr Sarnacki 2016-03-07 14:35:19 +01:00
commit bfb1b69374
31 changed files with 347 additions and 13 deletions

View File

@ -1,5 +1,6 @@
{
"predef": [
"server",
"document",
"window",
"-Promise",

View File

@ -47,5 +47,11 @@ export default ActiveModelAdapter.extend({
}
return this._super(...arguments);
},
// this can be removed once this PR is merged and live:
// https://github.com/emberjs/data/pull/4204
findRecord(store, type, id, snapshot) {
return this.ajax(this.buildURL(type.modelName, id, snapshot, 'findRecord'), 'GET');
}
});

View File

@ -54,5 +54,11 @@ export default RESTAdapter.extend({
pathForType: function(modelName, id) {
var underscored = Ember.String.underscore(modelName);
return id ? underscored : Ember.String.pluralize(underscored);
},
// this can be removed once this PR is merged and live:
// https://github.com/emberjs/data/pull/4204
findRecord(store, type, id, snapshot) {
return this.ajax(this.buildURL(type.modelName, id, snapshot, 'findRecord'), 'GET');
}
});

View File

@ -2,6 +2,7 @@ import Ember from 'ember';
export default Ember.Component.extend({
logBinding: 'job.log',
classNames: ['job-log'],
didReceiveAttrs: function(options) {
this._super(...arguments);
@ -25,7 +26,10 @@ export default Ember.Component.extend({
},
setupLog(job) {
job.get('log').fetch();
this.set('error', false);
job.get('log').fetch().then(function() { }, () => {
this.set('error', true);
});
job.subscribe();
}
});

View File

@ -28,12 +28,14 @@ var Request = Ember.Object.extend({
return $.ajax({
url: this.redirectTo(xhr),
type: 'GET',
success: this.handlers.text
success: (body) => {
Ember.run(this, function() { this.handlers.text(body); });
}
});
} else if (this.isJson(xhr, body)) {
return this.handlers.json(body);
return Ember.run(this, function() { this.handlers.json(body); });
} else {
return this.handlers.text(body);
return Ember.run(this, function() { this.handlers.text(body); });
}
},
@ -44,6 +46,7 @@ var Request = Ember.Object.extend({
},
isJson(xhr, body) {
// Firefox can't see the Content-Type header on the xhr response due to the wrong
// status code 204. Should be some redirect code but that doesn't work with CORS.
var type = xhr.getResponseHeader('Content-Type') || '';

View File

@ -16,6 +16,14 @@ var Serializer = V2FallbackSerializer.extend({
return result;
},
normalizeSingleResponse: function(store, primaryModelClass, payload, id, requestType) {
if (payload.commit) {
payload.build.commit = payload.commit;
delete payload.build.commit_id;
}
return this._super(...arguments);
},
normalizeArrayResponse: function(store, primaryModelClass, payload, id, requestType) {
var result;
if (payload.commits) {

View File

@ -25,6 +25,14 @@ export default V2FallbackSerializer.extend({
return this._super(modelClass, resourceHash);
},
normalizeSingleResponse: function(store, primaryModelClass, payload, id, requestType) {
if (payload.commit) {
payload.job.commit = payload.commit;
delete payload.job.commit_id;
}
return this._super(...arguments);
},
normalizeArrayResponse: function(store, primaryModelClass, payload, id, requestType) {
var result;
if (payload.commits) {

View File

@ -1,5 +1,9 @@
{{#if log.isLoaded}}
{{log-content job=job log=log}}
{{#if error}}
<p class="notice">There was an error while trying to fetch the log.</p>
{{else}}
{{loading-indicator}}
{{#if log.isLoaded}}
{{log-content job=job log=log}}
{{else}}
{{loading-indicator}}
{{/if}}
{{/if}}

View File

@ -15,8 +15,11 @@
"moment": "~2.9.0",
"jquery-timeago": "~1.4.1",
"pusher": "~2.2.3",
"pretender": "0.1.0",
"ember-resolver": "~0.1.20"
"ember-resolver": "~0.1.20",
"pretender": "~0.12.0",
"lodash": "~3.7.0",
"Faker": "~3.0.0",
"ceibo": "1.0.0"
},
"resolutions": {
"ember": "2.2.1",

View File

@ -2,7 +2,7 @@
module.exports = function(environment) {
var ENV = {
useV3API: false,
useV3API: true,
modulePrefix: 'travis',
environment: environment,
baseURL: '/',
@ -77,6 +77,9 @@ module.exports = function(environment) {
// ENV.APP.LOG_TRANSITIONS = true;
// ENV.APP.LOG_TRANSITIONS_INTERNAL = true;
// ENV.APP.LOG_VIEW_LOOKUPS = true;
ENV['ember-cli-mirage'] = {
enabled: false
}
}
if (environment === 'test') {
@ -91,10 +94,13 @@ module.exports = function(environment) {
ENV.APP.rootElement = '#ember-testing';
ENV.apiEndpoint = '';
ENV.statusPageStatusUrl = null;
}
if (environment === 'production') {
ENV['ember-cli-mirage'] = {
enabled: false
}
}
// TODO: I insert values from ENV here, but in production

139
mirage/config.js Normal file
View File

@ -0,0 +1,139 @@
import Ember from 'ember';
import Mirage from 'ember-cli-mirage';
export default function() {
let _turnIntoV3Singular = function(type, record) {
if(record.attrs) {
record = record.attrs;
}
record['@type'] = type;
record['@href'] = `/${type}/${record.id}`;
return record;
};
let turnIntoV3 = function(type, payload) {
let response;
if(Ember.isArray(payload)) {
let records = payload.map( (record) => { return _turnIntoV3Singular(type, record); } );
let pluralized = Ember.String.pluralize(type);
response = {};
response['@type'] = pluralized;
response['@href'] = `/${pluralized}`;
response[pluralized] = records;
} else {
response = _turnIntoV3Singular(type, payload);
}
return response;
};
this.get('/repos', function(schema, request) {
return turnIntoV3('repository', schema.repository.all());
});
this.get('/repo/:slug', function(schema, request) {
let repos = schema.repository.where({ slug: decodeURIComponent(request.params.slug) });
return turnIntoV3('repository', repos[0]);
});
this.get('/jobs/:id', function(schema, request) {
let job = schema.job.find(request.params.id).attrs;
return {job: job, commit: schema.commit.find(job.commit_id).attrs};
});
this.get('/jobs', function(schema, request) {
return {jobs: schema.job.all()};
});
this.get('/builds/:id', function(schema, request) {
let build = schema.build.find(request.params.id).attrs;
return {build: build, commit: schema.commit.find(build.commit_id).attrs};
});
this.get('/jobs/:id/log', function(schema, request) {
let log = schema.log.find(request.params.id);
if(log) {
return { log: { parts: [{ id: log.attrs.id, number: 1, content: log.attrs.content}] }};
} else {
return new Mirage.Response(404, {}, {});
}
});
// These comments are here to help you get started. Feel free to delete them.
/*
Config (with defaults).
Note: these only affect routes defined *after* them!
*/
// this.urlPrefix = ''; // make this `http://localhost:8080`, for example, if your API is on a different server
// this.namespace = ''; // make this `api`, for example, if your API is namespaced
// this.timing = 400; // delay for each request, automatically set to 0 during testing
/*
Route shorthand cheatsheet
*/
/*
GET shorthands
// Collections
this.get('/contacts');
this.get('/contacts', 'users');
this.get('/contacts', ['contacts', 'addresses']);
// Single objects
this.get('/contacts/:id');
this.get('/contacts/:id', 'user');
this.get('/contacts/:id', ['contact', 'addresses']);
*/
/*
POST shorthands
this.post('/contacts');
this.post('/contacts', 'user'); // specify the type of resource to be created
*/
/*
PUT shorthands
this.put('/contacts/:id');
this.put('/contacts/:id', 'user'); // specify the type of resource to be updated
*/
/*
DELETE shorthands
this.del('/contacts/:id');
this.del('/contacts/:id', 'user'); // specify the type of resource to be deleted
// Single object + related resources. Make sure parent resource is first.
this.del('/contacts/:id', ['contact', 'addresses']);
*/
/*
Function fallback. Manipulate data in the db via
- db.{collection}
- db.{collection}.find(id)
- db.{collection}.where(query)
- db.{collection}.update(target, attrs)
- db.{collection}.remove(target)
// Example: return a single object with related models
this.get('/contacts/:id', function(db, request) {
var contactId = +request.params.id;
return {
contact: db.contacts.find(contactId),
addresses: db.addresses.where({contact_id: contactId})
};
});
*/
}
/*
You can optionally export a config that is only loaded during tests
export function testConfig() {
}
*/

View File

@ -0,0 +1,4 @@
import Mirage/*, {faker} */ from 'ember-cli-mirage';
export default Mirage.Factory.extend({
});

View File

@ -0,0 +1,4 @@
import Mirage/*, {faker} */ from 'ember-cli-mirage';
export default Mirage.Factory.extend({
});

View File

@ -0,0 +1,4 @@
import Mirage/*, {faker} */ from 'ember-cli-mirage';
export default Mirage.Factory.extend({
});

View File

@ -0,0 +1,20 @@
/*
This is an example factory definition.
Create more files in this directory to define additional factories.
*/
import Mirage/*, {faker} */ from 'ember-cli-mirage';
export default Mirage.Factory.extend({
// name: 'Pete', // strings
// age: 20, // numbers
// tall: true, // booleans
// email: function(i) { // and functions
// return 'person' + i + '@test.com';
// },
// firstName: faker.name.firstName, // using faker
// lastName: faker.name.firstName,
// zipCode: faker.address.zipCode
});

5
mirage/factories/job.js Normal file
View File

@ -0,0 +1,5 @@
import Mirage/*, {faker} */ from 'ember-cli-mirage';
export default Mirage.Factory.extend({
});

5
mirage/factories/log.js Normal file
View File

@ -0,0 +1,5 @@
import Mirage/*, {faker} */ from 'ember-cli-mirage';
export default Mirage.Factory.extend({
content: 'Hello log'
});

View File

@ -0,0 +1,7 @@
import Mirage from 'ember-cli-mirage';
export default Mirage.Factory.extend({
slug: 'travis-ci/travis-web',
githubLanguage: 'ruby',
active: true
});

4
mirage/models/build.js Normal file
View File

@ -0,0 +1,4 @@
import { Model } from 'ember-cli-mirage';
export default Model.extend({
});

4
mirage/models/commit.js Normal file
View File

@ -0,0 +1,4 @@
import { Model } from 'ember-cli-mirage';
export default Model.extend({
});

4
mirage/models/job.js Normal file
View File

@ -0,0 +1,4 @@
import { Model } from 'ember-cli-mirage';
export default Model.extend({
});

4
mirage/models/log.js Normal file
View File

@ -0,0 +1,4 @@
import { Model } from 'ember-cli-mirage';
export default Model.extend({
});

View File

@ -0,0 +1,4 @@
import { Model } from 'ember-cli-mirage';
export default Model.extend({
});

View File

@ -0,0 +1,7 @@
export default function(/* server */) {
// Seed your development database using your factories. This
// data will not be loaded in your tests.
// server.createList('contact', 10);
}

View File

@ -0,0 +1,4 @@
import { JSONAPISerializer } from 'ember-cli-mirage';
export default JSONAPISerializer.extend({
});

View File

@ -34,6 +34,8 @@
"ember-cli-htmlbars-inline-precompile": "^0.3.1",
"ember-cli-inject-live-reload": "^1.3.1",
"ember-cli-inline-images": "^0.0.4",
"ember-cli-mirage": "0.2.0-beta.7",
"ember-cli-page-object": "1.0.0",
"ember-cli-pendo": "drogus/ember-cli-pendo",
"ember-cli-pretender": "0.3.1",
"ember-cli-qunit": "^1.2.1",

View File

@ -1,5 +1,6 @@
{
"predef": [
"server",
"document",
"window",
"location",

View File

@ -0,0 +1,48 @@
import { test } from 'qunit';
import moduleForAcceptance from 'travis/tests/helpers/module-for-acceptance';
import jobPage from 'travis/tests/pages/job';
moduleForAcceptance('Acceptance | job view');
test('visiting job-view', function(assert) {
let repo = server.create('repository', {slug: 'travis-ci/travis-web'});
let branch = server.create('branch', {});
let commit = server.create('commit', {author_email: 'mrt@travis-ci.org', author_name: 'Mr T', committer_email: 'mrt@travis-ci.org', committer_name: 'Mr T', branch: 'acceptance-tests', message: 'This is a message', branch_is_default: true});
let build = server.create('build', {repository_id: repo.id, state: 'passed', commit_id: commit.id});
let job = server.create('job', {number: '1234.1', reposiptoy_id: repo.id, state: 'passed', build_id: build.id, commit_id: commit.id});
let log = server.create('log', { id: job.id });
visit('/travis-ci/travis-web/jobs/'+ job.id);
andThen(function() {
assert.equal(jobPage.branch, 'acceptance-tests');
assert.equal(jobPage.message, 'acceptance-tests This is a message');
assert.equal(jobPage.state, '#1234.1 passed');
assert.equal(jobPage.author, 'Mr T authored and committed');
assert.equal(jobPage.log, 'Hello log');
});
});
test('handling log error', function(assert) {
let repo = server.create('repository', {slug: 'travis-ci/travis-web'});
let branch = server.create('branch', {});
let commit = server.create('commit', {author_email: 'mrt@travis-ci.org', author_name: 'Mr T', committer_email: 'mrt@travis-ci.org', committer_name: 'Mr T', branch: 'acceptance-tests', message: 'This is a message', branch_is_default: true});
let build = server.create('build', {repository_id: repo.id, state: 'passed', commit_id: commit.id});
let job = server.create('job', {number: '1234.1', reposiptoy_id: repo.id, state: 'passed', build_id: build.id, commit_id: commit.id});
visit('/travis-ci/travis-web/jobs/'+ job.id);
andThen(function() {
assert.equal(jobPage.branch, 'acceptance-tests');
assert.equal(jobPage.message, 'acceptance-tests This is a message');
assert.equal(jobPage.state, '#1234.1 passed');
assert.equal(jobPage.author, 'Mr T authored and committed');
assert.equal(jobPage.logError, 'There was an error while trying to fetch the log.');
});
});

View File

@ -2,4 +2,5 @@ import Ember from 'ember';
export default function destroyApp(application) {
Ember.run(application, 'destroy');
server.shutdown();
}

14
tests/pages/job.js Normal file
View File

@ -0,0 +1,14 @@
import PageObject from 'travis/tests/page-object';
let {
text
} = PageObject;
export default PageObject.create({
branch: text('.commit-branch'),
message: text('.build-title'),
state: text('.build-status'),
author: text('.commit-author'),
log: text('#log'),
logError: text('.job-log .notice')
});

View File

@ -1,8 +1,6 @@
import { test, moduleForComponent } from 'ember-qunit';
import Ember from 'ember';
var server = null;
moduleForComponent('travis-status', 'TravisStatusComponent', {
unit: true
});
@ -11,6 +9,7 @@ test('adds incident class to .status-circle', function() {
var component;
expect(3);
component = this.subject();
component.statusPageStatusUrl = "https://status-url.example.com";
component.getStatus = function() {
return new Ember.RSVP.Promise(function(resolve, reject) {
return resolve({
@ -20,6 +19,7 @@ test('adds incident class to .status-circle', function() {
});
});
};
ok(!component.get('status'), 'status is initially not set');
this.render();
equal(component.get('status'), 'major', 'status is updated from the API');