[Ivan Diaz] - Add initial ruby api testing setup

[Ivan Diaz] - Add environment variables to PHP database configuration

[Ivan Diaz] - Add mocha-chai-sinon unit testing architecture

[Ivan Diaz] - Add frontend test to readme

[Ivan Diaz] - FrontEnd - Update form/button unit testing

[Ivan Diaz] - Remove warning dependencies

[Ivan Diaz] - Remove bacon from requires

Revert "[Ivan Diaz] - Remove bacon from requires"

This reverts commit eb909b3c19e87d722076270216b8401d73ca9f9b.

[Ivan Diaz] - FrontEnd - Remove gemfile.lock

[Ivan Diaz] - FrontEnd - Remove bundle

Remove abstract getProps

[Ivan Diaz] - Debugging ruby libs

global database variable [skip ci]

[Ivan Diaz] - Use global database variable

[Ivan Diaz] - Use value instead of id

libs.rb edited online with Bitbucket

[Ivan Diaz] - Add default mysql values, remove api comments
This commit is contained in:
Ivan Diaz 2016-05-10 22:35:36 -03:00
parent 661502051c
commit 67bcab2f5e
15 changed files with 136 additions and 78 deletions

View File

@ -22,6 +22,11 @@ OpenSupports v4.0
Now that `gulp dev` is running, the server is up as well and serving files from the `/build` directory. Any changes in the `/src` directory will be automatically processed by Gulp and the changes will be injected to any open browsers pointed at the proxy address. Now that `gulp dev` is running, the server is up as well and serving files from the `/build` directory. Any changes in the `/src` directory will be automatically processed by Gulp and the changes will be injected to any open browsers pointed at the proxy address.
#### Frontend Unit Testing
1. Do the steps described before
2. Install mocha "sudo npm install -g mocha"
3. Run `npm test` to run the tests
### Getting up and running BACK-END (server folder) ### Getting up and running BACK-END (server folder)
1. Clone this repo 1. Clone this repo

View File

@ -13,13 +13,15 @@
"npm": "^2.1.x" "npm": "^2.1.x"
}, },
"scripts": { "scripts": {
"test": "export NODE_PATH=src && jest" "test": "export NODE_PATH=src && mocha src/lib-test/preprocessor.js --compilers js:babel-core/register --recursive src/**/__tests__/*-test.js"
}, },
"devDependencies": { "devDependencies": {
"babel-core": "^5.8.22", "babel-core": "^5.8.22",
"babel-register": "^6.7.2",
"babelify": "^6.1.x", "babelify": "^6.1.x",
"browser-sync": "^2.7.13", "browser-sync": "^2.7.13",
"browserify": "^10.2.6", "browserify": "^10.2.6",
"chai": "^3.5.0",
"debowerify": "^1.3.1", "debowerify": "^1.3.1",
"del": "^1.2.0", "del": "^1.2.0",
"express": "^4.13.1", "express": "^4.13.1",
@ -38,10 +40,14 @@
"gulp-uglify": "^1.2.0", "gulp-uglify": "^1.2.0",
"gulp-util": "^3.0.6", "gulp-util": "^3.0.6",
"humps": "^0.6.0", "humps": "^0.6.0",
"jest-cli": "^0.5.10",
"jquery-mockjax": "^2.1.0", "jquery-mockjax": "^2.1.0",
"jsdom": "^8.4.1",
"morgan": "^1.6.1", "morgan": "^1.6.1",
"proxyquire": "^1.7.4",
"react-addons-test-utils": "^15.0.1",
"run-sequence": "^1.1.1", "run-sequence": "^1.1.1",
"sinon": "^1.17.3",
"sinon-chai": "^2.8.0",
"vinyl-source-stream": "^1.1.0", "vinyl-source-stream": "^1.1.0",
"watchify": "^3.2.x" "watchify": "^3.2.x"
}, },
@ -51,28 +57,13 @@
"jquery": "^2.1.4", "jquery": "^2.1.4",
"lodash": "^3.10.0", "lodash": "^3.10.0",
"messageformat": "^0.2.2", "messageformat": "^0.2.2",
"react": "^0.14.6", "react": "^15.0.1",
"react-document-title": "^1.0.2", "react-document-title": "^1.0.2",
"react-dom": "^0.14.6", "react-dom": "^15.0.1",
"react-google-recaptcha": "^0.5.2", "react-google-recaptcha": "^0.5.2",
"react-motion": "^0.3.0", "react-motion": "^0.3.0",
"react-router": "^2.0.0-rc5", "react-router": "^2.4.0",
"reflux": "^0.2.9", "reflux": "^0.4.1",
"sessionstorage": "0.0.1" "sessionstorage": "0.0.1"
},
"jest": {
"scriptPreprocessor": "./preprocessor.js",
"testFileExtensions": [
"es6",
"js"
],
"moduleFileExtensions": [
"js",
"json",
"es6"
],
"unmockedModulePathPatterns": [
"react"
]
} }
} }

View File

@ -1,19 +1,14 @@
jest.dontMock('../button.js'); let Button = require('core-components/button');
import React from 'react'; describe('Button component', function () {
import Button from '../button.js';
let TestUtils = React.addons.TestUtils; it('should render children correctly', function () {
describe('Button', function () {
it('should render children', function () {
let button = TestUtils.renderIntoDocument( let button = TestUtils.renderIntoDocument(
<Button> <Button>test content</Button>
testcontent
</Button>
); );
expect(button.getDOMNode().textContent).toEqual('testcontent'); expect(ReactDOM.findDOMNode(button).textContent).to.eql('test content');
}); });
it('should add passed types to class', function () { it('should add passed types to class', function () {
@ -26,11 +21,11 @@ describe('Button', function () {
types.forEach(function (type) { types.forEach(function (type) {
let button = TestUtils.renderIntoDocument( let button = TestUtils.renderIntoDocument(
<Button type={type}> <Button type={type}>
testcontent test content
</Button> </Button>
); );
expect(button.getDOMNode().getAttribute('class')).toContain('button-' + type); expect(ReactDOM.findDOMNode(button).getAttribute('class')).to.include('button-' + type);
}); });
}); });
}); });

View File

@ -1,26 +1,24 @@
jest.dontMock('core-components/form.js'); const Form = require('core-components/form');
jest.dontMock('core-components/form.js'); const Input = require('core-components/input');
import React from 'react'; describe('Form component', function () {
import Form from 'core-components/form.js'; let form, inputs, onSubmit = stub();
import Input from 'core-components/input.js';
let TestUtils = React.addons.TestUtils; beforeEach(function () {
form = TestUtils.renderIntoDocument(
describe('Form', function () { <Form onSubmit={onSubmit}>
let results = TestUtils.renderIntoDocument( <div>
<Form onSubmit={jest.genMockFunction()}> <Input name="first" value="value1"/>
<div> <Input name="second" value="value2" />
<Input name="first" value="value1"/> </div>
<Input name="second" value="value2" /> <Input name="third" value="value3" />
</div> </Form>
<Input name="third" value="value3" /> );
</Form> inputs = TestUtils.scryRenderedComponentsWithType(form, Input);
); });
let inputs = TestUtils.scryRenderedComponentsWithType(results, Input);
it('should store input value in form state', function () { it('should store input value in form state', function () {
expect(results.state.form).toEqual({ expect(form.state.form).to.deep.equal({
first: 'value1', first: 'value1',
second: 'value2', second: 'value2',
third: 'value3' third: 'value3'
@ -30,7 +28,7 @@ describe('Form', function () {
it('should update form state if an input value changes', function () { it('should update form state if an input value changes', function () {
inputs[0].props.onChange({ target: {value: 'value4'}}); inputs[0].props.onChange({ target: {value: 'value4'}});
expect(results.state.form).toEqual({ expect(form.state.form).to.deep.equal({
first: 'value4', first: 'value4',
second: 'value2', second: 'value2',
third: 'value3' third: 'value3'
@ -38,7 +36,7 @@ describe('Form', function () {
}); });
it('should update input value if state value changes', function () { it('should update input value if state value changes', function () {
results.setState({ form.setState({
form: { form: {
first: 'value6', first: 'value6',
second: 'value7', second: 'value7',
@ -46,14 +44,14 @@ describe('Form', function () {
} }
}); });
expect(inputs[0].props.value).toEqual('value6'); expect(inputs[0].props.value).to.equal('value6');
expect(inputs[1].props.value).toEqual('value7'); expect(inputs[1].props.value).to.equal('value7');
expect(inputs[2].props.value).toEqual('value8'); expect(inputs[2].props.value).to.equal('value8');
}); });
it('should call onSubmit callback when form is submitted', function () { it('should call onSubmit callback when form is submitted', function () {
TestUtils.Simulate.submit(results.getDOMNode()); TestUtils.Simulate.submit(ReactDOM.findDOMNode(form));
expect(results.props.onSubmit).toBeCalledWith(results.state.form); expect(form.props.onSubmit).to.have.been.calledWith(form.state.form);
}); });
}); });

View File

@ -1,7 +1,6 @@
import React from 'react'; var React = require('react');
import classNames from 'classnames'; var classNames = require('classnames');
import Router from 'react-router'; var callback = require('lib-core/callback');
import callback from 'lib-core/callback';
let Button = React.createClass({ let Button = React.createClass({

View File

@ -0,0 +1,20 @@
var jsdom = require('jsdom').jsdom;
global.document = jsdom('<html><body></body></html>');
global.window = document.defaultView;
global.navigator = {
userAgent: 'node.js'
};
global.React = require('react');
global.ReactDOM = require('react-dom');
global.chai = require('chai');
global.expect = chai.expect;
global.sinon = require('sinon');
global.stub = sinon.stub;
global.proxyquire = require('proxyquire');
global.ReactMock = require('lib-test/react-mock');
chai.use(require('sinon-chai'));
global.TestUtils = require('react-addons-test-utils');
global.requireUnit = function (path, mocks) {
return proxyquire(process.cwd() + '/src/' + path + '.js', mocks)
};

9
client/src/lib-test/react-mock.js vendored Normal file
View File

@ -0,0 +1,9 @@
const React = require('react');
module.exports = function () {
return React.createClass({
render() {
return <div {...this.props} />;
}
});
};

View File

@ -1,2 +0,0 @@
---
BUNDLE_NO_INSTALL: false

View File

@ -1,5 +1,3 @@
source "https://rubygems.org" source "https://rubygems.org"
gem 'mysql' gem 'mysql'
gem 'bacon' gem 'bacon'
gem 'net/http'
gem 'uri'

View File

@ -6,11 +6,22 @@ def request(path, data)
return JSON.parse(response.body) return JSON.parse(response.body)
end end
def getRow(table, id) class Database
database = Mysql.new('localhost', 'root', '', 'os_dev') def initialize()
queryResponse = database.query("select * from #{table} where id='#{id.to_s}'") mysqlUser = ENV['MYSQL_USER'] || 'root';
mysqlPass = ENV['MYSQL_PASSWORD'] || '';
@connection = Mysql.new('localhost', mysqlUser , mysqlPass, 'development')
end
database.close def close()
@connection.close
end
return queryResponse.fetch_hash def getRow(table, value, field = 'id')
queryResponse = @connection.query("select * from #{table} where #{field}='#{value.to_s}'")
return queryResponse.fetch_hash
end
end end
$database = Database.new

View File

@ -0,0 +1,11 @@
class Scripts
def self.createUser(email = 'steve@jobs.com', password = 'custompassword')
response = request('/user/signup', {
'email' => email,
'password' => password
})
if response['status'] === 'fail'
raise "Could not create user"
end
end

View File

@ -0,0 +1,24 @@
describe '/user/login' do
before do
@loginEmail = 'login@os4.com'
@loginPass = 'loginpass'
Scripts.createUser(@loginEmail, @loginPass)
end
it 'should fail if password is incorrect' do
result = request('/user/login', {
email: @loginEmail,
pass: 'some_incorrect_password'
})
(result['status']).should.equal('fail')
end
it 'should login correctly' do
end
it 'should fail if already logged in' do
end

View File

@ -5,7 +5,7 @@ describe '/user/signup' do
'password' => 'custom' 'password' => 'custom'
}) })
userRow = getRow('users', response['data']['userId']) userRow = $database.getRow('users', response['data']['userId'])
(userRow['email']).should.equal('steve@jobs.com') (userRow['email']).should.equal('steve@jobs.com')
end end

View File

@ -1,5 +1,5 @@
<?php <?php
$mysql_host = 'localhost'; $mysql_host = 'localhost';
$mysql_user = 'os_dev'; $mysql_user = $_ENV['MYSQL_USER'] || 'root';
$mysql_password = 'os_dev'; $mysql_password = $_ENV['MYSQL_PASSWORD'] || '';
$mysql_database = 'os_dev'; $mysql_database = 'development';

View File

@ -5,7 +5,6 @@ abstract class DataStore {
protected $_bean; protected $_bean;
abstract protected function getDefaultProperties(); abstract protected function getDefaultProperties();
abstract static protected function getProps();
public static function getDataStore($value, $property = 'id') { public static function getDataStore($value, $property = 'id') {
$bean = RedBean::findOne(static::TABLE, static::validateProp($property) . ' =:value', array( $bean = RedBean::findOne(static::TABLE, static::validateProp($property) . ' =:value', array(