diff --git a/package.json b/package.json index 12a389075..6022a2dcf 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ }, "devDependencies": { "autoprefixer": "^7.1.1", - "babel-cli": "^6.23.0", + "babel-cli": "^6.24.1", "babel-core": "^6.24.1", "babel-eslint": "^7.2.3", "babel-loader": "^7.0.0", @@ -46,6 +46,7 @@ "babel-preset-env": "^1.4.0", "babel-preset-react": "^6.24.1", "chai": "^4.0.2", + "chokidar": "^1.7.0", "core-js": "^2.4.1", "css-loader": "^0.28.1", "eslint": "^3.19.0", @@ -75,6 +76,7 @@ "start": "node source/server.js", "compile": "NODE_ENV='production' webpack --config source/webpack.config.js", "surge": "npm run compile && surge --domain scientific-wish.surge.sh -p ./ && rm -rf dist/", - "test": "mocha-webpack --webpack-config source/webpack.config.js --require source-map-support/register --require __tests__/helpers/browser.js \"__tests__/**/*.test.js\"" + "test": "mocha-webpack --webpack-config source/webpack.config.js --require source-map-support/register --require test/helpers/browser.js \"test/**/*.test.js\"", + "test-fast": "babel-node --presets babel-preset-flow,babel-preset-env --plugins transform-class-properties test/helpers/runner.js" } } diff --git a/source/components/Results.js b/source/components/Results.js index 1ed9c3f60..0d85a9cb0 100644 --- a/source/components/Results.js +++ b/source/components/Results.js @@ -6,8 +6,8 @@ import { withRouter } from 'react-router' import R from 'ramda' import './Results.css' import {capitalise0} from '../utils' -import {computeRuleValue} from 'Engine/traverse' -import {encodeRuleName, getObjectives} from 'Engine/rules' +import {computeRuleValue} from '../engine/traverse' +import {encodeRuleName, getObjectives} from '../engine/rules' let fmt = new Intl.NumberFormat('fr-FR').format let humanFigure = decimalDigits => value => fmt(value.toFixed(decimalDigits)) diff --git a/source/components/Satisfaction.js b/source/components/Satisfaction.js index 61099a72f..f6c586d2f 100644 --- a/source/components/Satisfaction.js +++ b/source/components/Satisfaction.js @@ -1,5 +1,5 @@ import React, {Component} from 'react' -import HoverDecorator from 'Components/HoverDecorator' +import HoverDecorator from './HoverDecorator' import 'whatwg-fetch' import {connect} from 'react-redux' import './Satisfaction.css' diff --git a/source/components/Simulateur.js b/source/components/Simulateur.js index 286e6bc9e..7ac101ef6 100644 --- a/source/components/Simulateur.js +++ b/source/components/Simulateur.js @@ -5,13 +5,13 @@ import {START_CONVERSATION} from '../actions' import R from 'ramda' import {Redirect, Link, withRouter} from 'react-router-dom' import Aide from './Aide' -import {createMarkdownDiv} from 'Engine/marked' -import {rules, findRuleByName, decodeRuleName} from 'Engine/rules' -import 'Components/conversation/conversation.css' -import 'Components/Simulateur.css' +import {createMarkdownDiv} from '../engine/marked' +import {rules, findRuleByName, decodeRuleName} from '../engine/rules' +import './conversation/conversation.css' +import './Simulateur.css' import classNames from 'classnames' import {capitalise0} from '../utils' -import Satisfaction from 'Components/Satisfaction' +import Satisfaction from './Satisfaction' import Helmet from 'react-helmet' let situationSelector = formValueSelector('conversation') diff --git a/source/components/rule/Algorithm.js b/source/components/rule/Algorithm.js index d14f79f8f..ab75b56b2 100644 --- a/source/components/rule/Algorithm.js +++ b/source/components/rule/Algorithm.js @@ -2,8 +2,8 @@ import React from 'react' import classNames from 'classnames' import R from 'ramda' import {AttachDictionary} from '../AttachDictionary' -import knownMecanisms from 'Engine/known-mecanisms.yaml' -import marked from 'Engine/marked' +import knownMecanisms from '../../engine/known-mecanisms.yaml' +import marked from '../../engine/marked' @AttachDictionary(knownMecanisms) export default class Algorithm extends React.Component { diff --git a/source/components/rule/Examples.js b/source/components/rule/Examples.js index 02fe288bc..9e73e9667 100644 --- a/source/components/rule/Examples.js +++ b/source/components/rule/Examples.js @@ -5,8 +5,8 @@ import { rules, decodeRuleName, disambiguateRuleReference -} from "Engine/rules.js" -import { analyseSituation } from "Engine/traverse" +} from "../../engine/rules.js" +import { analyseSituation } from "../../engine/traverse" import "./Examples.css" export default class Examples extends Component { diff --git a/source/components/rule/References.js b/source/components/rule/References.js index b71451418..70ccbd49f 100644 --- a/source/components/rule/References.js +++ b/source/components/rule/References.js @@ -1,6 +1,6 @@ import React from 'react' import R from 'ramda' -import references from 'Règles/ressources/références/références.yaml' +import references from '../../../../règles/ressources/références/références.yaml' import './References.css' export default ({refs}) => ( @@ -18,7 +18,7 @@ export default ({refs}) => ( {domain} {refData.image && - } + } diff --git a/source/components/rule/Rule.js b/source/components/rule/Rule.js index 652e8ef5c..6d4e16e30 100644 --- a/source/components/rule/Rule.js +++ b/source/components/rule/Rule.js @@ -4,11 +4,11 @@ import {connect} from 'react-redux' import {formValueSelector} from 'redux-form' import R from 'ramda' import './Rule.css' -import {rules, decodeRuleName} from 'Engine/rules.js' -import mockSituation from 'Engine/mockSituation.yaml' -import {analyseSituation} from 'Engine/traverse' +import {rules, decodeRuleName} from '../../engine/rules.js' +import mockSituation from '../../engine/mockSituation.yaml' +import {analyseSituation} from '../../engine/traverse' import {START_CONVERSATION} from '../../actions' -import possiblesDestinataires from 'Règles/ressources/destinataires/destinataires.yaml' +import possiblesDestinataires from '../../../règles/ressources/destinataires/destinataires.yaml' import {capitalise0} from '../../utils' import References from './References' import Algorithm from './Algorithm' @@ -89,7 +89,7 @@ export default class Rule extends Component { :
{destinataireData.image && - } + } {!destinataireData.image &&
{destinataire}
} diff --git a/source/containers/Layout.js b/source/containers/Layout.js index 95e45e096..2ff45f747 100644 --- a/source/containers/Layout.js +++ b/source/containers/Layout.js @@ -2,13 +2,13 @@ import React, { Component } from 'react' import './Layout.css' import './reset.css' import {Link, Route, BrowserRouter as Router, Switch} from 'react-router-dom' -import HomeEmbauche from 'Components/HomeEmbauche' -import HomeSyso from 'Components/HomeSyso' -import Rule from 'Components/rule/Rule' -import Route404 from 'Components/Route404' -import Contact from 'Components/Contact' -import Simulateur from 'Components/Simulateur' -import Results from 'Components/Results' +import HomeEmbauche from '../components/HomeEmbauche' +import HomeSyso from '../components/HomeSyso' +import Rule from '../components/rule/Rule' +import Route404 from '../components/Route404' +import Contact from '../components/Contact' +import Simulateur from '../components/Simulateur' +import Results from '../components/Results' export default class Layout extends Component { diff --git a/source/engine/generateQuestions.js b/source/engine/generateQuestions.js index d2611dbd5..6a8483319 100644 --- a/source/engine/generateQuestions.js +++ b/source/engine/generateQuestions.js @@ -1,9 +1,9 @@ import React from 'react' -import Explicable from 'Components/conversation/Explicable' +import Explicable from '../components/conversation/Explicable' import R from 'ramda' -import Question from 'Components/conversation/Question' -import Input from 'Components/conversation/Input' -import formValueTypes from 'Components/conversation/formValueTypes' +import Question from '../components/conversation/Question' +import Input from '../components/conversation/Input' +import formValueTypes from '../components/conversation/formValueTypes' import {analyseSituation} from './traverse' import {formValueSelector} from 'redux-form' import { STEP_ACTION, START_CONVERSATION} from '../actions' diff --git a/source/engine/load-rules.js b/source/engine/load-rules.js index 9360b4ddd..ca1c9fbbb 100644 --- a/source/engine/load-rules.js +++ b/source/engine/load-rules.js @@ -1,7 +1,45 @@ import R from 'ramda' +// This is a mock of webpack's require.context, for testing purposes +if (typeof require.context === 'undefined') { + const fs = require('fs'); + const path = require('path'); + + require.context = (base = '.', scanSubDirectories = false, regularExpression = /\.js$/) => { + const yaml = require('js-yaml'); + + const files = {}; + + function readDirectory(directory) { + fs.readdirSync(directory).forEach((file) => { + const fullPath = path.resolve(directory, file); + + if (fs.statSync(fullPath).isDirectory()) { + if (scanSubDirectories) readDirectory(fullPath); + + return; + } + + if (!regularExpression.test(fullPath)) return; + + files[fullPath] = true; + }); + } + + readDirectory(path.resolve(__dirname, base)); + + function Module(file) { + return yaml.safeLoad(fs.readFileSync(file, 'utf8')); + } + + Module.keys = () => Object.keys(files); + + return Module; + }; +} + // This array can't be generated, as the arguments to require.context must be literals :-| -let directoryLoaders = +let directoryLoaders = [ require.context('../../règles/rémunération-travail/cdd', true, /([A-Za-z\u00C0-\u017F]|\.|-|_)+.yaml$/), diff --git a/source/engine/rules.js b/source/engine/rules.js index 0ea54cfb4..9fb295980 100644 --- a/source/engine/rules.js +++ b/source/engine/rules.js @@ -153,12 +153,8 @@ export let collectMissingVariables = (groupMethod='groupByMissingVariable') => a let isVariant = R.path(['formule', 'une possibilité']) export let findVariantsAndRecords = - (allRules, memo, dottedName, childDottedName) => { - console.log("memo",memo) - console.log("dottedName",dottedName) - console.log("childDottedName",childDottedName) - let {variantGroups, recordGroups} = memo, - child = findRuleByDottedName(allRules, dottedName), + (allRules, {variantGroups, recordGroups}, dottedName, childDottedName) => { + let child = findRuleByDottedName(allRules, dottedName), parentDottedName = parentName(dottedName), parent = findRuleByDottedName(allRules, parentDottedName) if (isVariant(parent)) { diff --git a/source/engine/traverse-common-jsx.js b/source/engine/traverse-common-jsx.js index 7f51401e8..bc79be27b 100644 --- a/source/engine/traverse-common-jsx.js +++ b/source/engine/traverse-common-jsx.js @@ -2,7 +2,7 @@ import React from 'react' import R from 'ramda' import classNames from 'classnames' import {Link} from 'react-router-dom' -import {encodeRuleName} from 'Engine/rules' +import {encodeRuleName} from './rules' let treatValue = data => data == null diff --git a/__tests__/generateQuestions.test.js b/test/generateQuestions.test.js similarity index 100% rename from __tests__/generateQuestions.test.js rename to test/generateQuestions.test.js diff --git a/__tests__/helpers/browser.js b/test/helpers/browser.js similarity index 100% rename from __tests__/helpers/browser.js rename to test/helpers/browser.js diff --git a/test/helpers/runner.js b/test/helpers/runner.js new file mode 100644 index 000000000..ec3534ec9 --- /dev/null +++ b/test/helpers/runner.js @@ -0,0 +1,51 @@ +import Mocha from 'mocha'; +import chokidar from 'chokidar'; + +const fs = require('fs'); + +const noop = () => {} + +const loadYaml = (module, filename) => { + const yaml = require('js-yaml'); + module.exports = yaml.safeLoad(fs.readFileSync(filename, 'utf8')); +} + +const loadNearley = (module, filename) => { + var nearley = require('nearley/lib/nearley.js'); + var compile = require('nearley/lib/compile.js'); + var generate = require('nearley/lib/generate.js'); + var grammar = require('nearley/lib/nearley-language-bootstrapped.js'); + + var parser = new nearley.Parser(grammar.ParserRules, grammar.ParserStart); + parser.feed(fs.readFileSync(filename, 'utf8')); + var compilation = compile(parser.results[0], {}); + var content = generate(compilation, 'Grammar'); + + module._compile(content,filename) +} + +require.extensions['.yaml'] = loadYaml +require.extensions['.ne'] = loadNearley +require.extensions['.css'] = noop + +let fileList = []; +function runSuite() { + Object.keys( require.cache ).forEach( key => delete require.cache[ key ] ); + const mocha = new Mocha( { reporter: 'dot' } ); + fileList.forEach( filepath => mocha.addFile( filepath ) ); + mocha.run(); +} + +/** + * Chokidar watches all the files for any kind of change and calls the run function + * from above. Read more: https://github.com/paulmillr/chokidar + * @param {string} a glob of files to watch + * @param {object} settings + */ +chokidar.watch( 'test/**/*.test.js', { persistent: true } ) + .on( 'add', path => fileList.push( path ) ) + .on( 'change', path => runSuite() ) + .on( 'ready', () => runSuite() ); + +chokidar.watch( 'source/**/*.js', { persistent: true } ) + .on( 'change', path => runSuite() ) diff --git a/test/mocha.opts b/test/mocha.opts new file mode 100644 index 000000000..4092fbfd4 --- /dev/null +++ b/test/mocha.opts @@ -0,0 +1,2 @@ +--compilers js:babel-register +test/**/*.test.js diff --git a/__tests__/rules.test.js b/test/rules.test.js similarity index 100% rename from __tests__/rules.test.js rename to test/rules.test.js diff --git a/__tests__/traverse.test.js b/test/traverse.test.js similarity index 100% rename from __tests__/traverse.test.js rename to test/traverse.test.js diff --git a/__tests__/utils.test.js b/test/utils.test.js similarity index 100% rename from __tests__/utils.test.js rename to test/utils.test.js