Setup stub amo app
This commit is contained in:
Родитель
ee61073045
Коммит
1a52291801
|
@ -29,8 +29,9 @@ Generic scripts that don't need env vars. Use these for development:
|
|||
|
||||
| Script | Description |
|
||||
|------------------------|-----------------------------------------------------|
|
||||
| npm run dev:search | Starts the dev server (search app) |
|
||||
| npm run dev:amo | Starts the dev server (amo) |
|
||||
| npm run dev:disco | Starts the dev server (discovery pane) |
|
||||
| npm run dev:search | Starts the dev server (search app) |
|
||||
| npm run eslint | Lints the JS |
|
||||
| npm run stylelint | Lints the SCSS |
|
||||
| npm run lint | Runs all the JS + SCSS linters |
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
module.exports = {
|
||||
|
||||
};
|
|
@ -8,6 +8,7 @@ const path = require('path');
|
|||
|
||||
const appName = process.env.NODE_APP_INSTANCE || null;
|
||||
const validAppNames = [
|
||||
'amo',
|
||||
'disco',
|
||||
'search',
|
||||
];
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
"build": "bin/build-checks.js && better-npm-run build",
|
||||
"extract-locales": "better-npm-run extract-locales",
|
||||
"clean": "rimraf './dist/*+(css|js|map|json)' './webpack-assets.json'",
|
||||
"dev:amo": "better-npm-run dev:amo",
|
||||
"dev:disco": "better-npm-run dev:disco",
|
||||
"dev:search": "better-npm-run dev:search",
|
||||
"eslint": "eslint .",
|
||||
|
@ -28,6 +29,12 @@
|
|||
"NODE_PATH": "./:./src"
|
||||
}
|
||||
},
|
||||
"dev:amo": {
|
||||
"command": "better-npm-run start-dev",
|
||||
"env": {
|
||||
"NODE_APP_INSTANCE": "amo"
|
||||
}
|
||||
},
|
||||
"dev:disco": {
|
||||
"command": "better-npm-run start-dev",
|
||||
"env": {
|
||||
|
@ -56,7 +63,7 @@
|
|||
}
|
||||
},
|
||||
"servertest": {
|
||||
"command": "mocha --compilers js:babel-register --timeout 10000 tests/server/",
|
||||
"command": "mocha --compilers js:babel-register --timeout 10000 --recursive tests/server/",
|
||||
"env": {
|
||||
"NODE_PATH": "./:./src",
|
||||
"NODE_ENV": "production"
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
import makeClient from 'core/client/base';
|
||||
import routes from './routes';
|
||||
import createStore from './store';
|
||||
|
||||
// Initialize the tracking.
|
||||
import 'core/tracking';
|
||||
|
||||
makeClient(routes, createStore);
|
|
@ -0,0 +1,27 @@
|
|||
import React, { PropTypes } from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
|
||||
import 'amo/css/App.scss';
|
||||
import translate from 'core/i18n/translate';
|
||||
|
||||
|
||||
export class App extends React.Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.node,
|
||||
i18n: PropTypes.object.isRequired,
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children, i18n } = this.props;
|
||||
return (
|
||||
<div className="amo">
|
||||
<Helmet
|
||||
defaultTitle={i18n.gettext('Add-ons for Firefox')}
|
||||
/>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default translate({ withRef: true })(App);
|
|
@ -0,0 +1,11 @@
|
|||
import React from 'react';
|
||||
|
||||
export default class Home extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h1>AMO Home Page Hello World</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
@import "~normalize.css";
|
||||
@import "~core/css/inc/lib";
|
||||
@import "~core/css/inc/mixins";
|
||||
|
||||
html,
|
||||
body {
|
||||
background: red;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
import React from 'react';
|
||||
import { IndexRoute, Route } from 'react-router';
|
||||
|
||||
import App from './containers/App';
|
||||
import Home from './containers/Home';
|
||||
|
||||
export default (
|
||||
<Route path="/" component={App}>
|
||||
<IndexRoute component={Home} />
|
||||
<Route path="/:lang/" component={Home} />
|
||||
</Route>
|
||||
);
|
|
@ -0,0 +1,14 @@
|
|||
import { createStore as _createStore, combineReducers } from 'redux';
|
||||
import { reducer as reduxAsyncConnect } from 'redux-async-connect';
|
||||
import { middleware } from 'core/store';
|
||||
|
||||
import addons from 'core/reducers/addons';
|
||||
import api from 'core/reducers/api';
|
||||
|
||||
export default function createStore(initialState = {}) {
|
||||
return _createStore(
|
||||
combineReducers({ addons, api, reduxAsyncConnect }),
|
||||
initialState,
|
||||
middleware(),
|
||||
);
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import React from 'react';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import {
|
||||
findRenderedComponentWithType,
|
||||
renderIntoDocument,
|
||||
} from 'react-addons-test-utils';
|
||||
|
||||
import App from 'amo/containers/App';
|
||||
import I18nProvider from 'core/i18n/Provider';
|
||||
|
||||
import { getFakeI18nInst } from 'tests/client/helpers';
|
||||
|
||||
|
||||
describe('App', () => {
|
||||
it('renders its children', () => {
|
||||
class MyComponent extends React.Component {
|
||||
render() {
|
||||
return <p>The component</p>;
|
||||
}
|
||||
}
|
||||
const root = findRenderedComponentWithType(renderIntoDocument(
|
||||
<I18nProvider i18n={getFakeI18nInst()}>
|
||||
<App>
|
||||
<MyComponent />
|
||||
</App>
|
||||
</I18nProvider>), App).getWrappedInstance();
|
||||
|
||||
const rootNode = findDOMNode(root);
|
||||
assert.equal(rootNode.tagName.toLowerCase(), 'div');
|
||||
assert.equal(rootNode.querySelector('p').textContent, 'The component');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,16 @@
|
|||
import React from 'react';
|
||||
import { findDOMNode } from 'react-dom';
|
||||
import {
|
||||
renderIntoDocument,
|
||||
} from 'react-addons-test-utils';
|
||||
|
||||
import Home from 'amo/containers/Home';
|
||||
|
||||
|
||||
describe('Home', () => {
|
||||
it('renders a heading', () => {
|
||||
const root = renderIntoDocument(<Home />);
|
||||
const rootNode = findDOMNode(root);
|
||||
assert.include(rootNode.querySelector('h1').textContent, 'AMO Home Page');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
import createStore from 'amo/store';
|
||||
|
||||
describe('search createStore', () => {
|
||||
it('sets the reducers', () => {
|
||||
const store = createStore();
|
||||
assert.deepEqual(
|
||||
Object.keys(store.getState()).sort(),
|
||||
['addons', 'api', 'reduxAsyncConnect']);
|
||||
});
|
||||
|
||||
it('creates an empty store', () => {
|
||||
const store = createStore();
|
||||
assert.deepEqual(store.getState().addons, {});
|
||||
});
|
||||
});
|
|
@ -20,7 +20,7 @@ const apiHosts = {
|
|||
};
|
||||
|
||||
|
||||
describe('CSP Config', () => {
|
||||
describe('CSP Config Defaults', () => {
|
||||
afterEach(() => {
|
||||
process.env.NODE_ENV = 'production';
|
||||
});
|
||||
|
@ -85,46 +85,3 @@ describe('CSP Config', () => {
|
|||
assert.deepEqual(cspConfig.mediaSrc, ["'none'"]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('App Specific CSP Config', () => {
|
||||
afterEach(() => {
|
||||
process.env.NODE_ENV = 'production';
|
||||
delete process.env.NODE_APP_INSTANCE;
|
||||
});
|
||||
|
||||
it('should set style-src for disco', () => {
|
||||
process.env.NODE_APP_INSTANCE = 'disco';
|
||||
const config = requireUncached('config');
|
||||
const cspConfig = config.get('CSP').directives;
|
||||
assert.deepEqual(cspConfig.styleSrc, ['https://addons-discovery.cdn.mozilla.net']);
|
||||
});
|
||||
|
||||
it('should set script-src for disco', () => {
|
||||
process.env.NODE_APP_INSTANCE = 'disco';
|
||||
const config = requireUncached('config');
|
||||
const cspConfig = config.get('CSP').directives;
|
||||
assert.deepEqual(cspConfig.scriptSrc, [
|
||||
'https://addons-discovery.cdn.mozilla.net', 'https://www.google-analytics.com']);
|
||||
});
|
||||
|
||||
it('should set media-src for disco', () => {
|
||||
process.env.NODE_APP_INSTANCE = 'disco';
|
||||
const config = requireUncached('config');
|
||||
const cspConfig = config.get('CSP').directives;
|
||||
assert.deepEqual(cspConfig.mediaSrc, ['https://addons-discovery.cdn.mozilla.net']);
|
||||
});
|
||||
|
||||
it('should set img-src for disco', () => {
|
||||
process.env.NODE_APP_INSTANCE = 'disco';
|
||||
const config = requireUncached('config');
|
||||
const cspConfig = config.get('CSP').directives;
|
||||
assert.sameMembers(cspConfig.imgSrc, [
|
||||
"'self'",
|
||||
'data:',
|
||||
'https://addons.cdn.mozilla.net',
|
||||
'https://addons-discovery.cdn.mozilla.net',
|
||||
'https://www.google-analytics.com',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,53 +1,59 @@
|
|||
import { getClientConfig } from 'core/utils';
|
||||
import { assert } from 'chai';
|
||||
import requireUncached from 'require-uncached';
|
||||
import config from 'config';
|
||||
|
||||
const appsList = config.get('validAppNames');
|
||||
|
||||
|
||||
describe('Config', () => {
|
||||
afterEach(() => {
|
||||
process.env.NODE_ENV = 'production';
|
||||
delete process.env.NODE_APP_INSTANCE;
|
||||
});
|
||||
|
||||
it('should not ever have disableSSR set to true', () => {
|
||||
const config = requireUncached('config');
|
||||
assert.equal(config.get('disableSSR'), false);
|
||||
});
|
||||
for (const appName of appsList) {
|
||||
it(`should not ever have disableSSR set to true for ${appName}`, () => {
|
||||
const conf = requireUncached('config');
|
||||
assert.equal(conf.get('disableSSR'), false);
|
||||
});
|
||||
|
||||
it('should provide a production config by default', () => {
|
||||
process.env.NODE_ENV = 'production';
|
||||
const config = requireUncached('config');
|
||||
const clientConfig = getClientConfig(config);
|
||||
assert.equal(config.get('apiHost'), 'https://addons.mozilla.org');
|
||||
assert.equal(clientConfig.apiHost, 'https://addons.mozilla.org');
|
||||
assert.equal(config.util.getEnv('NODE_ENV'), 'production');
|
||||
});
|
||||
it(`should provide a production conf by default for ${appName}`, () => {
|
||||
process.env.NODE_ENV = 'production';
|
||||
const conf = requireUncached('config');
|
||||
const clientConfig = getClientConfig(conf);
|
||||
assert.equal(conf.get('apiHost'), 'https://addons.mozilla.org');
|
||||
assert.equal(clientConfig.apiHost, 'https://addons.mozilla.org');
|
||||
assert.equal(conf.util.getEnv('NODE_ENV'), 'production');
|
||||
});
|
||||
|
||||
it('should provide a dev config', () => {
|
||||
process.env.NODE_ENV = 'dev';
|
||||
const config = requireUncached('config');
|
||||
const clientConfig = getClientConfig(config);
|
||||
assert.equal(config.get('apiHost'), 'https://addons-dev.allizom.org');
|
||||
assert.equal(clientConfig.apiHost, 'https://addons-dev.allizom.org');
|
||||
assert.equal(config.util.getEnv('NODE_ENV'), 'dev');
|
||||
});
|
||||
it(`should provide a dev conf for ${appName}`, () => {
|
||||
process.env.NODE_ENV = 'dev';
|
||||
const conf = requireUncached('config');
|
||||
const clientConfig = getClientConfig(conf);
|
||||
assert.equal(conf.get('apiHost'), 'https://addons-dev.allizom.org');
|
||||
assert.equal(clientConfig.apiHost, 'https://addons-dev.allizom.org');
|
||||
assert.equal(conf.util.getEnv('NODE_ENV'), 'dev');
|
||||
});
|
||||
|
||||
it('should provide a stage config', () => {
|
||||
process.env.NODE_ENV = 'stage';
|
||||
const config = requireUncached('config');
|
||||
const clientConfig = getClientConfig(config);
|
||||
assert.equal(config.get('apiHost'), 'https://addons.allizom.org');
|
||||
assert.equal(clientConfig.apiHost, 'https://addons.allizom.org');
|
||||
assert.equal(config.util.getEnv('NODE_ENV'), 'stage');
|
||||
});
|
||||
it(`should provide a stage conf for ${appName}`, () => {
|
||||
process.env.NODE_ENV = 'stage';
|
||||
const conf = requireUncached('config');
|
||||
const clientConfig = getClientConfig(conf);
|
||||
assert.equal(conf.get('apiHost'), 'https://addons.allizom.org');
|
||||
assert.equal(clientConfig.apiHost, 'https://addons.allizom.org');
|
||||
assert.equal(conf.util.getEnv('NODE_ENV'), 'stage');
|
||||
});
|
||||
|
||||
it('should provide a development config', () => {
|
||||
process.env.NODE_ENV = 'development';
|
||||
const config = requireUncached('config');
|
||||
const clientConfig = getClientConfig(config);
|
||||
assert.equal(config.get('apiHost'), 'https://addons-dev.allizom.org');
|
||||
assert.equal(clientConfig.apiHost, 'https://addons-dev.allizom.org');
|
||||
assert.equal(config.util.getEnv('NODE_ENV'), 'development');
|
||||
});
|
||||
it(`should provide a development conf for ${appName}`, () => {
|
||||
process.env.NODE_ENV = 'development';
|
||||
const conf = requireUncached('config');
|
||||
const clientConfig = getClientConfig(conf);
|
||||
assert.equal(conf.get('apiHost'), 'https://addons-dev.allizom.org');
|
||||
assert.equal(clientConfig.apiHost, 'https://addons-dev.allizom.org');
|
||||
assert.equal(conf.util.getEnv('NODE_ENV'), 'development');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
@ -58,18 +64,18 @@ describe('Config Environment Variables', () => {
|
|||
});
|
||||
|
||||
it('should allow host overrides', () => {
|
||||
let config = requireUncached('config');
|
||||
assert.equal(config.get('serverHost'), '127.0.0.1', 'initial host is set');
|
||||
let conf = requireUncached('config');
|
||||
assert.equal(conf.get('serverHost'), '127.0.0.1', 'initial host is set');
|
||||
process.env.SERVER_HOST = '0.0.0.0';
|
||||
config = requireUncached('config');
|
||||
assert.equal(config.get('serverHost'), '0.0.0.0', 'host is overidden');
|
||||
conf = requireUncached('config');
|
||||
assert.equal(conf.get('serverHost'), '0.0.0.0', 'host is overidden');
|
||||
});
|
||||
|
||||
it('should allow port overrides', () => {
|
||||
let config = requireUncached('config');
|
||||
assert.equal(config.get('serverPort'), '4000', 'Initial port is set');
|
||||
let conf = requireUncached('config');
|
||||
assert.equal(conf.get('serverPort'), '4000', 'Initial port is set');
|
||||
process.env.SERVER_PORT = '5000';
|
||||
config = requireUncached('config');
|
||||
assert.equal(config.get('serverPort'), '5000', 'Port is overidden');
|
||||
conf = requireUncached('config');
|
||||
assert.equal(conf.get('serverPort'), '5000', 'Port is overidden');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
import { assert } from 'chai';
|
||||
import requireUncached from 'require-uncached';
|
||||
import config from 'config';
|
||||
|
||||
const appsList = config.get('validAppNames');
|
||||
|
||||
describe('App Specific Frameguard Config', () => {
|
||||
afterEach(() => {
|
||||
|
@ -7,10 +10,13 @@ describe('App Specific Frameguard Config', () => {
|
|||
delete process.env.NODE_APP_INSTANCE;
|
||||
});
|
||||
|
||||
it('should default frameGuard to "deny"', () => {
|
||||
const config = requireUncached('config');
|
||||
const frameGuardConfig = config.get('frameGuard');
|
||||
assert.equal(frameGuardConfig.action, 'deny');
|
||||
assert.equal(frameGuardConfig.domain, undefined);
|
||||
});
|
||||
for (const appName of appsList) {
|
||||
it(`should default frameGuard to "deny" for ${appName} in production`, () => {
|
||||
process.env.NODE_APP_INSTANCE = appName;
|
||||
const conf = requireUncached('config');
|
||||
const frameGuardConfig = conf.get('frameGuard');
|
||||
assert.equal(frameGuardConfig.action, 'deny');
|
||||
assert.equal(frameGuardConfig.domain, undefined);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
import { assert } from 'chai';
|
||||
import requireUncached from 'require-uncached';
|
||||
|
||||
describe('Disco App Specific CSP Config', () => {
|
||||
let config;
|
||||
|
||||
afterEach(() => {
|
||||
process.env.NODE_ENV = 'production';
|
||||
delete process.env.NODE_APP_INSTANCE;
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
process.env.NODE_APP_INSTANCE = 'disco';
|
||||
config = requireUncached('config');
|
||||
});
|
||||
|
||||
it('should set style-src for disco', () => {
|
||||
const cspConfig = config.get('CSP').directives;
|
||||
assert.deepEqual(cspConfig.styleSrc, ['https://addons-discovery.cdn.mozilla.net']);
|
||||
});
|
||||
|
||||
it('should set script-src for disco', () => {
|
||||
const cspConfig = config.get('CSP').directives;
|
||||
assert.deepEqual(cspConfig.scriptSrc, [
|
||||
'https://addons-discovery.cdn.mozilla.net', 'https://www.google-analytics.com']);
|
||||
});
|
||||
|
||||
it('should set media-src for disco', () => {
|
||||
const cspConfig = config.get('CSP').directives;
|
||||
assert.deepEqual(cspConfig.mediaSrc, ['https://addons-discovery.cdn.mozilla.net']);
|
||||
});
|
||||
|
||||
it('should set img-src for disco', () => {
|
||||
const cspConfig = config.get('CSP').directives;
|
||||
assert.sameMembers(cspConfig.imgSrc, [
|
||||
"'self'",
|
||||
'data:',
|
||||
'https://addons.cdn.mozilla.net',
|
||||
'https://addons-discovery.cdn.mozilla.net',
|
||||
'https://www.google-analytics.com',
|
||||
]);
|
||||
});
|
||||
});
|
|
@ -6,10 +6,10 @@ import { assert } from 'chai';
|
|||
import { runServer } from 'core/server/base';
|
||||
import Policy from 'csp-parse';
|
||||
|
||||
import { checkSRI } from './helpers';
|
||||
import { checkSRI } from '../helpers';
|
||||
|
||||
|
||||
describe('GET requests', () => {
|
||||
describe('Discovery Pane GET requests', () => {
|
||||
let app;
|
||||
|
||||
before(() => runServer({ listen: false, app: 'disco' })
|
|
@ -6,9 +6,9 @@ import { assert } from 'chai';
|
|||
import { runServer } from 'core/server/base';
|
||||
import Policy from 'csp-parse';
|
||||
|
||||
import { checkSRI } from './helpers';
|
||||
import { checkSRI } from '../helpers';
|
||||
|
||||
describe('GET requests', () => {
|
||||
describe('Seach App GET requests', () => {
|
||||
let app;
|
||||
|
||||
before(() => runServer({ listen: false, app: 'search' })
|
Загрузка…
Ссылка в новой задаче