prettier all code and default prettier rules, fixes #182,#209 (#222)
* prettier all code and default prettier rules, fixes #182 * lint_problems.sh * typos * updateing readme
This commit is contained in:
Родитель
7a3b6e8ed0
Коммит
e22ce7fa2b
|
@ -1,5 +0,0 @@
|
|||
singleQuote: true
|
||||
trailingComma: all
|
||||
bracketSpacing: false
|
||||
jsxBracketSameLine: false
|
||||
parser: flow
|
43
README.md
43
README.md
|
@ -10,14 +10,13 @@ displaying information from those in a centralized place.
|
|||
|
||||
## Table of Contents
|
||||
|
||||
- [Cloning and getting into the Project Dir](#cloning-and-getting-into-the-project-dir)
|
||||
- [Setting up the development environment](#setting-up-the-development-environment)
|
||||
- [Starting the dev server](#starting-the-dev-server)
|
||||
- [Building](#building)
|
||||
- [Deploying to gh-pages](#deploying-to-gh-pages)
|
||||
- [Launching testsuite](#launching-testsuite)
|
||||
|
||||
|
||||
* [Cloning and getting into the Project Dir](#cloning-and-getting-into-the-project-dir)
|
||||
* [Setting up the development environment](#setting-up-the-development-environment)
|
||||
* [Starting the dev server](#starting-the-dev-server)
|
||||
* [Building](#building)
|
||||
* [Deploying to gh-pages](#deploying-to-gh-pages)
|
||||
* [Launching testsuite](#launching-testsuite)
|
||||
* [Linting](#linting)
|
||||
|
||||
## Cloning and getting into the Project Dir
|
||||
|
||||
|
@ -60,3 +59,31 @@ https://[your-github-username].github.io/delivery-dashboard/
|
|||
To run the testsuite, simply type:
|
||||
|
||||
$ yarn test
|
||||
|
||||
## Linting
|
||||
|
||||
We use [Prettier](https://prettier.io/) to format all `.js` and `.css` files
|
||||
according to the default configuration of Prettier.
|
||||
|
||||
When contributing, it is your responsibility to make sure all files you
|
||||
touch conform to the Prettier standard, but there are useful tools to make
|
||||
this easier.
|
||||
|
||||
Linting is checked in continuous integration for every pull request and
|
||||
build of `master`. If any file has any deviation from the Prettier output
|
||||
it will "break the build" and you're expected to fix it.
|
||||
|
||||
To make it easier to see what the potential linting problems are run:
|
||||
|
||||
```sh
|
||||
$ yarn lint
|
||||
```
|
||||
|
||||
It will report any errors and explain which files need attention. To
|
||||
make this more convenient you can simply run:
|
||||
|
||||
```sh
|
||||
$ yarn lint-fix
|
||||
```
|
||||
|
||||
which will directly fix the files that didn't pass.
|
||||
|
|
|
@ -30,14 +30,15 @@
|
|||
"deploy": "yarn run build && gh-pages --add --dist build/",
|
||||
"deploy-dev":
|
||||
"PUBLIC_URL=$npm_package_homepage_dev yarn run deploy --dest dev/",
|
||||
"lint": "prettier --list-different src/**/*.js",
|
||||
"lint-fix": "yarn lint --write",
|
||||
"lint":
|
||||
"prettier --list-different src/**/*.js src/**/*.css | scripts/lint_problems.sh",
|
||||
"lint-fix": "prettier --write src/**/*.js src/**/*.css",
|
||||
"flow": "flow",
|
||||
"flow-coverage":
|
||||
"flow-coverage-report -i 'src/**/*.js' -x 'src/**/*.test.js' -t html -t text",
|
||||
"check": "yarn lint && yarn flow",
|
||||
"precheck": "yarn run version-file",
|
||||
"version-file": "./update_version.sh"
|
||||
"version-file": "./scripts/update_version.sh"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-plugin-import": "1.6.3",
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Here goes miscellaneous scripts that help support the project
|
||||
infrastructure. None of these scripts should be used or necessary for
|
||||
runtime in production.
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eo pipefail
|
||||
|
||||
prelude() {
|
||||
echo "
|
||||
You have prettier linting errors!
|
||||
----------------------------------
|
||||
The following files would turn out different if you process them with prettier.
|
||||
|
||||
"
|
||||
}
|
||||
|
||||
any=false
|
||||
first=true
|
||||
while read line
|
||||
do
|
||||
$first && prelude
|
||||
echo "To fix:"
|
||||
echo " prettier --write ${line}"
|
||||
echo "To see:"
|
||||
echo " prettier ${line} | diff ${line} -"
|
||||
echo ""
|
||||
# echo "$line"
|
||||
any=true
|
||||
first=false
|
||||
done < "${1:-/dev/stdin}"
|
||||
|
||||
|
||||
$any && echo "
|
||||
If you're not interested in how they're different, consider running:
|
||||
|
||||
yarn run lint-fix
|
||||
"
|
||||
|
||||
$any && exit 1 || exit 0
|
141
src/App.js
141
src/App.js
|
@ -1,18 +1,18 @@
|
|||
// @flow
|
||||
import 'photon-ant';
|
||||
import * as React from 'react';
|
||||
import {Alert, Card, Icon, Layout, Spin, Tooltip} from 'antd';
|
||||
import './App.css';
|
||||
import {connect} from 'react-redux';
|
||||
import type {MapStateToProps} from 'react-redux';
|
||||
import "photon-ant";
|
||||
import * as React from "react";
|
||||
import { Alert, Card, Icon, Layout, Spin, Tooltip } from "antd";
|
||||
import "./App.css";
|
||||
import { connect } from "react-redux";
|
||||
import type { MapStateToProps } from "react-redux";
|
||||
import {
|
||||
capitalize,
|
||||
localUrlFromVersion,
|
||||
requestOngoingVersions,
|
||||
requestPollbotVersion,
|
||||
refreshStatus,
|
||||
requestStatus,
|
||||
} from './actions';
|
||||
requestStatus
|
||||
} from "./actions";
|
||||
import type {
|
||||
APIVersionData,
|
||||
CheckResult,
|
||||
|
@ -23,18 +23,18 @@ import type {
|
|||
Product,
|
||||
ReleaseInfo,
|
||||
State,
|
||||
Status,
|
||||
} from './types';
|
||||
import {products} from './types';
|
||||
Status
|
||||
} from "./types";
|
||||
import { products } from "./types";
|
||||
|
||||
const deliveryDashboardVersionData: APIVersionData = require('./version.json');
|
||||
const deliveryDashboardVersionData: APIVersionData = require("./version.json");
|
||||
|
||||
function requestNotificationPermission(): void {
|
||||
// Some browsers don't support Notification yet. I'm looking at you iOS Safari
|
||||
if ('Notification' in window) {
|
||||
if ("Notification" in window) {
|
||||
if (
|
||||
Notification.permission !== 'denied' &&
|
||||
Notification.permission !== 'granted'
|
||||
Notification.permission !== "denied" &&
|
||||
Notification.permission !== "granted"
|
||||
) {
|
||||
Notification.requestPermission();
|
||||
}
|
||||
|
@ -42,8 +42,8 @@ function requestNotificationPermission(): void {
|
|||
}
|
||||
|
||||
export const parseUrl = (
|
||||
url: string,
|
||||
): ?{service: string, product: Product, version: string} => {
|
||||
url: string
|
||||
): ?{ service: string, product: Product, version: string } => {
|
||||
const re = /^#(\w+)\/(\w+)\/([^/]+)\/?/; // Eg: #pollbot/firefox/50.0
|
||||
const parsed: ?(string[]) = url.match(re);
|
||||
if (!parsed) {
|
||||
|
@ -58,7 +58,7 @@ export const parseUrl = (
|
|||
return {
|
||||
service: service,
|
||||
product: maybeProduct,
|
||||
version: version,
|
||||
version: version
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -67,7 +67,7 @@ type AppProps = {
|
|||
dispatch: Dispatch,
|
||||
pollbotVersion: APIVersionData,
|
||||
shouldRefresh: boolean,
|
||||
errors: Error[],
|
||||
errors: Error[]
|
||||
};
|
||||
export class App extends React.Component<AppProps, void> {
|
||||
refreshIntervalId: ?IntervalID;
|
||||
|
@ -85,7 +85,7 @@ export class App extends React.Component<AppProps, void> {
|
|||
}
|
||||
this.refreshIntervalId = setInterval(
|
||||
() => this.props.dispatch(refreshStatus()),
|
||||
60000,
|
||||
60000
|
||||
);
|
||||
} else {
|
||||
this.stopAutoRefresh();
|
||||
|
@ -143,9 +143,9 @@ export class App extends React.Component<AppProps, void> {
|
|||
</Layout.Content>
|
||||
</Layout>
|
||||
<footer>
|
||||
Delivery dashboard version:{' '}
|
||||
Delivery dashboard version:{" "}
|
||||
<VersionLink versionData={deliveryDashboardVersionData} />
|
||||
-- Pollbot version:{' '}
|
||||
-- Pollbot version:{" "}
|
||||
<VersionLink versionData={this.props.pollbotVersion} />
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -153,28 +153,28 @@ export class App extends React.Component<AppProps, void> {
|
|||
}
|
||||
}
|
||||
const connectedAppMapStateToProps: MapStateToProps<*, *, *> = (
|
||||
state: State,
|
||||
state: State
|
||||
) => ({
|
||||
checkResults: state.checkResults,
|
||||
pollbotVersion: state.pollbotVersion,
|
||||
shouldRefresh: state.shouldRefresh,
|
||||
errors: state.errors,
|
||||
errors: state.errors
|
||||
});
|
||||
export const ConnectedApp = connect(
|
||||
connectedAppMapStateToProps,
|
||||
(dispatch: Dispatch) => ({dispatch: dispatch}),
|
||||
(dispatch: Dispatch) => ({ dispatch: dispatch })
|
||||
)(App);
|
||||
|
||||
const sideBarMapStateToProps: MapStateToProps<*, *, *> = (state: State) => ({
|
||||
versions: state.productVersions,
|
||||
versions: state.productVersions
|
||||
});
|
||||
const SideBar = connect(sideBarMapStateToProps)(ReleasesMenu);
|
||||
|
||||
type ReleasesMenuPropType = {
|
||||
versions: ProductVersions,
|
||||
versions: ProductVersions
|
||||
};
|
||||
|
||||
export function ReleasesMenu({versions}: ReleasesMenuPropType) {
|
||||
export function ReleasesMenu({ versions }: ReleasesMenuPropType) {
|
||||
const getVersion = (product, channel) => {
|
||||
const capitalizedChannel = capitalize(channel);
|
||||
if (versions.hasOwnProperty(product) && versions[product][channel]) {
|
||||
|
@ -195,30 +195,30 @@ export function ReleasesMenu({versions}: ReleasesMenuPropType) {
|
|||
<div className="releasesMenu">
|
||||
<h2>Firefox Releases</h2>
|
||||
<ul>
|
||||
<li>{getVersion('firefox', 'nightly')}</li>
|
||||
<li>{getVersion('firefox', 'beta')}</li>
|
||||
<li>{getVersion('devedition', 'devedition')}</li>
|
||||
<li>{getVersion('firefox', 'release')}</li>
|
||||
<li>{getVersion('firefox', 'esr')}</li>
|
||||
<li>{getVersion("firefox", "nightly")}</li>
|
||||
<li>{getVersion("firefox", "beta")}</li>
|
||||
<li>{getVersion("devedition", "devedition")}</li>
|
||||
<li>{getVersion("firefox", "release")}</li>
|
||||
<li>{getVersion("firefox", "esr")}</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const currentReleaseMapStateToProps: MapStateToProps<*, *, *> = (
|
||||
state: State,
|
||||
state: State
|
||||
) => ({
|
||||
checkResults: state.checkResults,
|
||||
releaseInfo: state.releaseInfo,
|
||||
productVersion: state.version,
|
||||
productVersion: state.version
|
||||
});
|
||||
const CurrentRelease = connect(currentReleaseMapStateToProps)(Dashboard);
|
||||
|
||||
type ErrorsPropType = {
|
||||
errors: Error[],
|
||||
errors: Error[]
|
||||
};
|
||||
|
||||
export function Errors({errors}: ErrorsPropType) {
|
||||
export function Errors({ errors }: ErrorsPropType) {
|
||||
if (!errors || errors.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
@ -243,16 +243,16 @@ export function Errors({errors}: ErrorsPropType) {
|
|||
type DashboardPropType = {
|
||||
checkResults: CheckResults,
|
||||
releaseInfo: ?ReleaseInfo,
|
||||
productVersion: [Product, string],
|
||||
productVersion: [Product, string]
|
||||
};
|
||||
|
||||
export function Dashboard({
|
||||
releaseInfo,
|
||||
checkResults,
|
||||
productVersion,
|
||||
productVersion
|
||||
}: DashboardPropType) {
|
||||
const [product, version] = productVersion;
|
||||
if (version === '') {
|
||||
if (version === "") {
|
||||
return (
|
||||
<p>
|
||||
Learn more about a specific version.
|
||||
|
@ -262,12 +262,12 @@ export function Dashboard({
|
|||
} else if (!releaseInfo) {
|
||||
return <Spin />;
|
||||
} else if (releaseInfo.message) {
|
||||
return <Errors errors={[['Pollbot error', releaseInfo.message]]} />;
|
||||
return <Errors errors={[["Pollbot error", releaseInfo.message]]} />;
|
||||
} else {
|
||||
return (
|
||||
<div>
|
||||
<h2 style={{marginBottom: '1em', display: 'flex', flexWrap: 'wrap'}}>
|
||||
{capitalize(product)} {version}{' '}
|
||||
<h2 style={{ marginBottom: "1em", display: "flex", flexWrap: "wrap" }}>
|
||||
{capitalize(product)} {version}{" "}
|
||||
<OverallStatus
|
||||
releaseInfo={releaseInfo}
|
||||
checkResults={checkResults}
|
||||
|
@ -290,18 +290,18 @@ export function Dashboard({
|
|||
|
||||
type OverallStatusPropType = {
|
||||
checkResults: CheckResults,
|
||||
releaseInfo: ReleaseInfo,
|
||||
releaseInfo: ReleaseInfo
|
||||
};
|
||||
|
||||
export function OverallStatus({
|
||||
releaseInfo,
|
||||
checkResults,
|
||||
checkResults
|
||||
}: OverallStatusPropType) {
|
||||
const checksStatus = releaseInfo.checks.map(
|
||||
check => checkResults[check.title],
|
||||
check => checkResults[check.title]
|
||||
);
|
||||
const allChecksCompleted = !checksStatus.some(
|
||||
result => typeof result === 'undefined',
|
||||
result => typeof result === "undefined"
|
||||
);
|
||||
if (!allChecksCompleted) {
|
||||
return <Spin />;
|
||||
|
@ -319,29 +319,34 @@ export function OverallStatus({
|
|||
});
|
||||
let type;
|
||||
let message;
|
||||
if (actionableChecks.some(status => status !== 'exists')) {
|
||||
type = 'error';
|
||||
message = 'Some checks failed';
|
||||
if (actionableChecks.some(status => status !== "exists")) {
|
||||
type = "error";
|
||||
message = "Some checks failed";
|
||||
} else {
|
||||
type = 'success';
|
||||
message = 'All checks are successful';
|
||||
type = "success";
|
||||
message = "All checks are successful";
|
||||
}
|
||||
return (
|
||||
<Alert message={message} type={type} showIcon style={{marginLeft: '1em'}} />
|
||||
<Alert
|
||||
message={message}
|
||||
type={type}
|
||||
showIcon
|
||||
style={{ marginLeft: "1em" }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
type DisplayCheckResultProps = {
|
||||
title: string,
|
||||
actionable: boolean,
|
||||
checkResult: CheckResult,
|
||||
checkResult: CheckResult
|
||||
};
|
||||
export class DisplayCheckResult extends React.PureComponent<
|
||||
DisplayCheckResultProps,
|
||||
void,
|
||||
void
|
||||
> {
|
||||
render() {
|
||||
const {title, actionable, checkResult} = this.props;
|
||||
const { title, actionable, checkResult } = this.props;
|
||||
let titleContent = title;
|
||||
if (!actionable) {
|
||||
titleContent = (
|
||||
|
@ -353,7 +358,7 @@ export class DisplayCheckResult extends React.PureComponent<
|
|||
);
|
||||
}
|
||||
return (
|
||||
<Card title={titleContent} style={{textAlign: 'center'}}>
|
||||
<Card title={titleContent} style={{ textAlign: "center" }}>
|
||||
{checkResult ? (
|
||||
<DisplayStatus
|
||||
status={checkResult.status}
|
||||
|
@ -373,24 +378,24 @@ export function DisplayStatus({
|
|||
status,
|
||||
message,
|
||||
url,
|
||||
actionable,
|
||||
actionable
|
||||
}: {
|
||||
status: Status,
|
||||
message: string,
|
||||
url: string,
|
||||
actionable: boolean,
|
||||
actionable: boolean
|
||||
}) {
|
||||
const getLabelClass = (status, actionable) => {
|
||||
if (status === 'error') {
|
||||
return 'error';
|
||||
if (status === "error") {
|
||||
return "error";
|
||||
}
|
||||
if (status === 'exists') {
|
||||
return 'success';
|
||||
if (status === "exists") {
|
||||
return "success";
|
||||
}
|
||||
if (actionable) {
|
||||
return 'warning';
|
||||
return "warning";
|
||||
}
|
||||
return 'info'; // It's a non actionable item.
|
||||
return "info"; // It's a non actionable item.
|
||||
};
|
||||
return (
|
||||
<a title={message} href={url}>
|
||||
|
@ -403,12 +408,12 @@ export function DisplayStatus({
|
|||
);
|
||||
}
|
||||
|
||||
function VersionLink({versionData}: {versionData: APIVersionData}) {
|
||||
function VersionLink({ versionData }: { versionData: APIVersionData }) {
|
||||
if (!versionData) {
|
||||
return null;
|
||||
}
|
||||
const {commit, source, version} = versionData;
|
||||
const sourceUrl = source.replace(/\.git/, '');
|
||||
const { commit, source, version } = versionData;
|
||||
const sourceUrl = source.replace(/\.git/, "");
|
||||
const url = `${sourceUrl}/commit/${commit}`;
|
||||
return <a href={url}>{version}</a>;
|
||||
}
|
||||
|
|
348
src/App.test.js
348
src/App.test.js
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import renderer from 'react-test-renderer';
|
||||
import {Provider} from 'react-redux';
|
||||
import {mount, shallow} from 'enzyme';
|
||||
import React from "react";
|
||||
import renderer from "react-test-renderer";
|
||||
import { Provider } from "react-redux";
|
||||
import { mount, shallow } from "enzyme";
|
||||
import {
|
||||
App,
|
||||
ConnectedApp,
|
||||
|
@ -11,19 +11,19 @@ import {
|
|||
Errors,
|
||||
OverallStatus,
|
||||
ReleasesMenu,
|
||||
parseUrl,
|
||||
} from './App';
|
||||
import {Alert, Spin, Tooltip} from 'antd';
|
||||
import createStore from './create-store';
|
||||
import {SERVER} from './PollbotAPI';
|
||||
import Enzyme from 'enzyme';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
parseUrl
|
||||
} from "./App";
|
||||
import { Alert, Spin, Tooltip } from "antd";
|
||||
import createStore from "./create-store";
|
||||
import { SERVER } from "./PollbotAPI";
|
||||
import Enzyme from "enzyme";
|
||||
import Adapter from "enzyme-adapter-react-16";
|
||||
|
||||
Enzyme.configure({adapter: new Adapter()});
|
||||
Enzyme.configure({ adapter: new Adapter() });
|
||||
|
||||
// Mock the Notification API.
|
||||
global.Notification = {
|
||||
requestPermission: jest.fn(),
|
||||
requestPermission: jest.fn()
|
||||
};
|
||||
|
||||
// Mock the localStorage API.
|
||||
|
@ -39,7 +39,7 @@ global.localStorage = (function() {
|
|||
},
|
||||
clear: function() {
|
||||
store = {};
|
||||
},
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
|
@ -49,22 +49,22 @@ global.localStorage = (function() {
|
|||
function fetchMocker(response) {
|
||||
return jest
|
||||
.fn()
|
||||
.mockImplementation(() => Promise.resolve({json: () => response}));
|
||||
.mockImplementation(() => Promise.resolve({ json: () => response }));
|
||||
}
|
||||
|
||||
global.fetch = fetchMocker({
|
||||
version: 'pollbot-version-number',
|
||||
commit: 'pollbot-commit-hash',
|
||||
source: 'https://github.com/mozilla/PollBot.git',
|
||||
name: 'pollbot',
|
||||
version: "pollbot-version-number",
|
||||
commit: "pollbot-commit-hash",
|
||||
source: "https://github.com/mozilla/PollBot.git",
|
||||
name: "pollbot"
|
||||
});
|
||||
|
||||
// Mock the delivery-dashboard version
|
||||
jest.mock('./version', () => ({
|
||||
version: 'version-number',
|
||||
commit: 'commit-hash',
|
||||
source: 'https://github.com/mozilla/delivery-dashboard.git',
|
||||
name: 'delivery-dashboard',
|
||||
jest.mock("./version", () => ({
|
||||
version: "version-number",
|
||||
commit: "commit-hash",
|
||||
source: "https://github.com/mozilla/delivery-dashboard.git",
|
||||
name: "delivery-dashboard"
|
||||
}));
|
||||
|
||||
beforeAll(() => {
|
||||
|
@ -75,35 +75,35 @@ afterAll(() => {
|
|||
jest.clearAllTimers();
|
||||
});
|
||||
|
||||
describe('<App />', () => {
|
||||
it('renders without crashing', () => {
|
||||
describe("<App />", () => {
|
||||
it("renders without crashing", () => {
|
||||
const app = renderer.create(
|
||||
<Provider store={createStore()}>
|
||||
<ConnectedApp />
|
||||
</Provider>,
|
||||
</Provider>
|
||||
);
|
||||
expect(app.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
it('requests for Notification permissions', () => {
|
||||
it("requests for Notification permissions", () => {
|
||||
renderer.create(
|
||||
<Provider store={createStore()}>
|
||||
<ConnectedApp />
|
||||
</Provider>,
|
||||
</Provider>
|
||||
);
|
||||
expect(global.Notification.requestPermission).toHaveBeenCalled();
|
||||
});
|
||||
it('requests PollBot for its version', () => {
|
||||
it("requests PollBot for its version", () => {
|
||||
renderer.create(
|
||||
<Provider store={createStore()}>
|
||||
<ConnectedApp />
|
||||
</Provider>,
|
||||
</Provider>
|
||||
);
|
||||
expect(global.fetch).toHaveBeenCalledWith(`${SERVER}/__version__`);
|
||||
});
|
||||
it('calls requestStatus(version) with the version from the hash', () => {
|
||||
global.window.location.hash = '#pollbot/firefox/123.0';
|
||||
it("calls requestStatus(version) with the version from the hash", () => {
|
||||
global.window.location.hash = "#pollbot/firefox/123.0";
|
||||
|
||||
const module = require('./actions');
|
||||
const module = require("./actions");
|
||||
module.requestStatus = jest.fn();
|
||||
|
||||
const store = createStore();
|
||||
|
@ -114,12 +114,12 @@ describe('<App />', () => {
|
|||
renderer.create(
|
||||
<Provider store={store}>
|
||||
<ConnectedApp />
|
||||
</Provider>,
|
||||
</Provider>
|
||||
);
|
||||
expect(module.requestStatus).toHaveBeenCalledWith('firefox', '123.0');
|
||||
expect(module.requestStatus).toHaveBeenCalledWith("firefox", "123.0");
|
||||
});
|
||||
it('sets up auto-refresh', () => {
|
||||
const module = require('./actions');
|
||||
it("sets up auto-refresh", () => {
|
||||
const module = require("./actions");
|
||||
module.requestStatus = jest.fn();
|
||||
module.refreshStatus = jest.fn();
|
||||
|
||||
|
@ -133,7 +133,7 @@ describe('<App />', () => {
|
|||
|
||||
// Shouldn't auto-refresh => stop auto refresh.
|
||||
expect(app.stopAutoRefresh).toHaveBeenCalledTimes(0);
|
||||
wrapper.setProps({shouldRefresh: false});
|
||||
wrapper.setProps({ shouldRefresh: false });
|
||||
expect(app.stopAutoRefresh).toHaveBeenCalledTimes(1);
|
||||
expect(app.refreshIntervalId).toBeNull();
|
||||
app.setUpAutoRefresh();
|
||||
|
@ -145,7 +145,7 @@ describe('<App />', () => {
|
|||
|
||||
// Should auto-refresh => start auto refresh.
|
||||
expect(app.refreshIntervalId).toBeNull();
|
||||
wrapper.setProps({shouldRefresh: true});
|
||||
wrapper.setProps({ shouldRefresh: true });
|
||||
app.setUpAutoRefresh();
|
||||
expect(app.stopAutoRefresh).toHaveBeenCalledTimes(2); // Not called again.
|
||||
expect(setInterval).toHaveBeenCalledTimes(1);
|
||||
|
@ -155,7 +155,7 @@ describe('<App />', () => {
|
|||
expect(module.refreshStatus).toHaveBeenCalledTimes(1);
|
||||
|
||||
// Should auto-refresh, but already set up => don't start auto refresh.
|
||||
wrapper.setProps({shouldRefresh: true});
|
||||
wrapper.setProps({ shouldRefresh: true });
|
||||
app.setUpAutoRefresh();
|
||||
expect(app.stopAutoRefresh).toHaveBeenCalledTimes(2); // Not called again.
|
||||
expect(setInterval).toHaveBeenCalledTimes(1); // Not called again.
|
||||
|
@ -163,7 +163,7 @@ describe('<App />', () => {
|
|||
expect(module.requestStatus).toHaveBeenCalledTimes(numCalledRequestStatus);
|
||||
expect(module.refreshStatus).toHaveBeenCalledTimes(1); // Not called again.
|
||||
});
|
||||
it('stops auto-refresh', () => {
|
||||
it("stops auto-refresh", () => {
|
||||
const app = shallow(<App dispatch={jest.fn()} />).instance();
|
||||
|
||||
// Shouldn't call clearInterval if not needed.
|
||||
|
@ -176,7 +176,7 @@ describe('<App />', () => {
|
|||
expect(clearInterval).toHaveBeenCalledWith(123);
|
||||
expect(app.refreshIntervalId).toBeNull();
|
||||
});
|
||||
it('stops the auto-refresh on unmount', () => {
|
||||
it("stops the auto-refresh on unmount", () => {
|
||||
const wrapper = shallow(<App dispatch={jest.fn()} />);
|
||||
const app = wrapper.instance();
|
||||
app.stopAutoRefresh = jest.fn();
|
||||
|
@ -185,63 +185,63 @@ describe('<App />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('parseUrl', () => {
|
||||
it('returns null for a non matching url', () => {
|
||||
expect(parseUrl('')).toBeNull();
|
||||
expect(parseUrl('#foobar')).toBeNull();
|
||||
describe("parseUrl", () => {
|
||||
it("returns null for a non matching url", () => {
|
||||
expect(parseUrl("")).toBeNull();
|
||||
expect(parseUrl("#foobar")).toBeNull();
|
||||
});
|
||||
it("returns null if the product isn't recognized", () => {
|
||||
expect(parseUrl('#pollbot/foobar/50.0')).toBeNull();
|
||||
expect(parseUrl("#pollbot/foobar/50.0")).toBeNull();
|
||||
});
|
||||
it('returns the proper structure for a matching url', () => {
|
||||
expect(parseUrl('#pollbot/firefox/50.0')).toEqual({
|
||||
service: 'pollbot',
|
||||
product: 'firefox',
|
||||
version: '50.0',
|
||||
it("returns the proper structure for a matching url", () => {
|
||||
expect(parseUrl("#pollbot/firefox/50.0")).toEqual({
|
||||
service: "pollbot",
|
||||
product: "firefox",
|
||||
version: "50.0"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('<ReleasesMenu />', () => {
|
||||
describe("<ReleasesMenu />", () => {
|
||||
it("displays a list of channels with spinners if there's no product versions yet", () => {
|
||||
const wrapper = mount(<ReleasesMenu versions={{}} />);
|
||||
const textContent = wrapper.text();
|
||||
expect(textContent).toContain('Nightly');
|
||||
expect(textContent).toContain('Beta');
|
||||
expect(textContent).toContain('Devedition');
|
||||
expect(textContent).toContain('Release');
|
||||
expect(textContent).toContain('Esr');
|
||||
expect(textContent).toContain("Nightly");
|
||||
expect(textContent).toContain("Beta");
|
||||
expect(textContent).toContain("Devedition");
|
||||
expect(textContent).toContain("Release");
|
||||
expect(textContent).toContain("Esr");
|
||||
});
|
||||
it("displays a list of channels with version numbers if there's product versions", () => {
|
||||
const wrapper = mount(
|
||||
<ReleasesMenu
|
||||
versions={{
|
||||
firefox: {
|
||||
nightly: '60.0a1',
|
||||
beta: '59.0b4',
|
||||
release: '58.0',
|
||||
esr: '52.6.0esr',
|
||||
nightly: "60.0a1",
|
||||
beta: "59.0b4",
|
||||
release: "58.0",
|
||||
esr: "52.6.0esr"
|
||||
},
|
||||
devedition: {
|
||||
devedition: '59.0b4',
|
||||
},
|
||||
devedition: "59.0b4"
|
||||
}
|
||||
}}
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
const textContent = wrapper.text();
|
||||
expect(textContent).toContain('Nightly: 60.0a1');
|
||||
expect(textContent).toContain('Beta: 59.0b4');
|
||||
expect(textContent).toContain('Devedition: 59.0b4');
|
||||
expect(textContent).toContain('Release: 58.0');
|
||||
expect(textContent).toContain('Esr: 52.6.0esr');
|
||||
expect(textContent).toContain("Nightly: 60.0a1");
|
||||
expect(textContent).toContain("Beta: 59.0b4");
|
||||
expect(textContent).toContain("Devedition: 59.0b4");
|
||||
expect(textContent).toContain("Release: 58.0");
|
||||
expect(textContent).toContain("Esr: 52.6.0esr");
|
||||
});
|
||||
});
|
||||
|
||||
describe('<Errors />', () => {
|
||||
it('displays a list of errors', () => {
|
||||
const wrapper = mount(<Errors errors={[['foo', 'bar']]} />);
|
||||
describe("<Errors />", () => {
|
||||
it("displays a list of errors", () => {
|
||||
const wrapper = mount(<Errors errors={[["foo", "bar"]]} />);
|
||||
expect(wrapper.text()).toContain(
|
||||
"Failed getting check result for 'foo': bar",
|
||||
"Failed getting check result for 'foo': bar"
|
||||
);
|
||||
});
|
||||
it("doesn't return anything if there's no errors", () => {
|
||||
|
@ -250,58 +250,58 @@ describe('<Errors />', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('<Dashboard />', () => {
|
||||
describe("<Dashboard />", () => {
|
||||
const releaseInfo = {
|
||||
channel: 'nightly',
|
||||
product: 'firefox',
|
||||
version: '50.0',
|
||||
channel: "nightly",
|
||||
product: "firefox",
|
||||
version: "50.0",
|
||||
checks: [
|
||||
{url: 'some-url', title: 'some title', actionable: true},
|
||||
{url: 'some-url-2', title: 'some title 2', actionable: false},
|
||||
],
|
||||
{ url: "some-url", title: "some title", actionable: true },
|
||||
{ url: "some-url-2", title: "some title 2", actionable: false }
|
||||
]
|
||||
};
|
||||
const checkResults = {
|
||||
'some title': {
|
||||
status: 'exists',
|
||||
message: 'check is successful',
|
||||
link: 'some link',
|
||||
},
|
||||
'some title 2': {
|
||||
status: 'exists',
|
||||
message: 'check is successful',
|
||||
link: 'some link',
|
||||
"some title": {
|
||||
status: "exists",
|
||||
message: "check is successful",
|
||||
link: "some link"
|
||||
},
|
||||
"some title 2": {
|
||||
status: "exists",
|
||||
message: "check is successful",
|
||||
link: "some link"
|
||||
}
|
||||
};
|
||||
it('displays a help text when no version is selected', () => {
|
||||
const wrapper = shallow(<Dashboard productVersion={['firefox', '']} />);
|
||||
it("displays a help text when no version is selected", () => {
|
||||
const wrapper = shallow(<Dashboard productVersion={["firefox", ""]} />);
|
||||
expect(wrapper.text()).toContain(
|
||||
'Learn more about a specific version. Select a version number from the left menu.',
|
||||
"Learn more about a specific version. Select a version number from the left menu."
|
||||
);
|
||||
});
|
||||
it('displays a spinner when a version is selected', () => {
|
||||
const wrapper = shallow(<Dashboard productVersion={['firefox', '50.0']} />);
|
||||
it("displays a spinner when a version is selected", () => {
|
||||
const wrapper = shallow(<Dashboard productVersion={["firefox", "50.0"]} />);
|
||||
expect(wrapper.find(Spin).length).toBe(1);
|
||||
});
|
||||
it("displays an error when there's a Pollbot error", () => {
|
||||
const wrapper = mount(
|
||||
<Dashboard
|
||||
productVersion={['firefox', '50.0']}
|
||||
releaseInfo={{message: 'error from pollbot'}}
|
||||
/>,
|
||||
productVersion={["firefox", "50.0"]}
|
||||
releaseInfo={{ message: "error from pollbot" }}
|
||||
/>
|
||||
);
|
||||
const error = wrapper.find(Errors);
|
||||
expect(error.length).toBe(1);
|
||||
expect(error.text()).toEqual(
|
||||
"Failed getting check result for 'Pollbot error': error from pollbot",
|
||||
"Failed getting check result for 'Pollbot error': error from pollbot"
|
||||
);
|
||||
});
|
||||
it('displays a list of check results when a release info is present', () => {
|
||||
it("displays a list of check results when a release info is present", () => {
|
||||
const wrapper = shallow(
|
||||
<Dashboard
|
||||
productVersion={['firefox', '50.0']}
|
||||
productVersion={["firefox", "50.0"]}
|
||||
releaseInfo={releaseInfo}
|
||||
checkResults={checkResults}
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find(Spin).length).toBe(0);
|
||||
expect(wrapper.find(DisplayCheckResult).length).toBe(2);
|
||||
|
@ -309,106 +309,106 @@ describe('<Dashboard />', () => {
|
|||
it("displays an extra icon and tooltip on the checks that aren't actionable", () => {
|
||||
const wrapper = mount(
|
||||
<Dashboard
|
||||
productVersion={['firefox', '50.0']}
|
||||
productVersion={["firefox", "50.0"]}
|
||||
releaseInfo={releaseInfo}
|
||||
checkResults={checkResults}
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
const tooltip = wrapper.find(Tooltip);
|
||||
expect(tooltip.length).toBe(1);
|
||||
expect(tooltip.text()).toEqual(' some title 2');
|
||||
expect(tooltip.prop('title')).toEqual('This check is not actionable');
|
||||
expect(tooltip.text()).toEqual(" some title 2");
|
||||
expect(tooltip.prop("title")).toEqual("This check is not actionable");
|
||||
});
|
||||
});
|
||||
|
||||
describe('<OverallStatus />', () => {
|
||||
describe("<OverallStatus />", () => {
|
||||
const releaseInfo = {
|
||||
channel: 'nightly',
|
||||
product: 'firefox',
|
||||
version: '50.0',
|
||||
channel: "nightly",
|
||||
product: "firefox",
|
||||
version: "50.0",
|
||||
checks: [
|
||||
{url: 'some-url', title: 'some title', actionable: true},
|
||||
{url: 'some-url-2', title: 'some title 2', actionable: false},
|
||||
],
|
||||
{ url: "some-url", title: "some title", actionable: true },
|
||||
{ url: "some-url-2", title: "some title 2", actionable: false }
|
||||
]
|
||||
};
|
||||
const incompleteCheckResults = {
|
||||
'some title': {
|
||||
status: 'exists',
|
||||
message: 'check is successful',
|
||||
link: 'some link',
|
||||
},
|
||||
"some title": {
|
||||
status: "exists",
|
||||
message: "check is successful",
|
||||
link: "some link"
|
||||
}
|
||||
};
|
||||
const checkResults = {
|
||||
'some title': {
|
||||
status: 'exists',
|
||||
message: 'check is successful',
|
||||
link: 'some link',
|
||||
},
|
||||
'some title 2': {
|
||||
status: 'exists',
|
||||
message: 'check is successful',
|
||||
link: 'some link',
|
||||
"some title": {
|
||||
status: "exists",
|
||||
message: "check is successful",
|
||||
link: "some link"
|
||||
},
|
||||
"some title 2": {
|
||||
status: "exists",
|
||||
message: "check is successful",
|
||||
link: "some link"
|
||||
}
|
||||
};
|
||||
it('displays a "success" label when all the results are successful', () => {
|
||||
const wrapper = mount(
|
||||
<OverallStatus releaseInfo={releaseInfo} checkResults={checkResults} />,
|
||||
<OverallStatus releaseInfo={releaseInfo} checkResults={checkResults} />
|
||||
);
|
||||
const status = wrapper.find(Alert);
|
||||
expect(status.prop('message')).toEqual('All checks are successful');
|
||||
expect(status.prop('type')).toEqual('success');
|
||||
expect(status.prop("message")).toEqual("All checks are successful");
|
||||
expect(status.prop("type")).toEqual("success");
|
||||
});
|
||||
it('displays an "success" label if some non actionable check results are unsuccessful', () => {
|
||||
const results = Object.assign({}, checkResults, {
|
||||
'some title 2': Object.assign({}, checkResults['some title 2'], {
|
||||
status: 'missing',
|
||||
}),
|
||||
"some title 2": Object.assign({}, checkResults["some title 2"], {
|
||||
status: "missing"
|
||||
})
|
||||
});
|
||||
const wrapper = mount(
|
||||
<OverallStatus releaseInfo={releaseInfo} checkResults={results} />,
|
||||
<OverallStatus releaseInfo={releaseInfo} checkResults={results} />
|
||||
);
|
||||
const status = wrapper.find(Alert);
|
||||
expect(status.prop('message')).toEqual('All checks are successful');
|
||||
expect(status.prop('type')).toEqual('success');
|
||||
expect(status.prop("message")).toEqual("All checks are successful");
|
||||
expect(status.prop("type")).toEqual("success");
|
||||
});
|
||||
it('displays an "error" label if some actionable check results are unsuccessful', () => {
|
||||
const results = Object.assign({}, checkResults, {
|
||||
'some title': Object.assign({}, checkResults['some title'], {
|
||||
status: 'missing',
|
||||
}),
|
||||
"some title": Object.assign({}, checkResults["some title"], {
|
||||
status: "missing"
|
||||
})
|
||||
});
|
||||
const wrapper = mount(
|
||||
<OverallStatus releaseInfo={releaseInfo} checkResults={results} />,
|
||||
<OverallStatus releaseInfo={releaseInfo} checkResults={results} />
|
||||
);
|
||||
const status = wrapper.find(Alert);
|
||||
expect(status.prop('message')).toEqual('Some checks failed');
|
||||
expect(status.prop('type')).toEqual('error');
|
||||
expect(status.prop("message")).toEqual("Some checks failed");
|
||||
expect(status.prop("type")).toEqual("error");
|
||||
});
|
||||
it('displays an "error" label if some actionable check results are errored', () => {
|
||||
const results = Object.assign({}, checkResults, {
|
||||
'some title': Object.assign({}, checkResults['some title'], {
|
||||
status: 'error',
|
||||
}),
|
||||
"some title": Object.assign({}, checkResults["some title"], {
|
||||
status: "error"
|
||||
})
|
||||
});
|
||||
const wrapper = mount(
|
||||
<OverallStatus releaseInfo={releaseInfo} checkResults={results} />,
|
||||
<OverallStatus releaseInfo={releaseInfo} checkResults={results} />
|
||||
);
|
||||
const status = wrapper.find(Alert);
|
||||
expect(status.prop('message')).toEqual('Some checks failed');
|
||||
expect(status.prop('type')).toEqual('error');
|
||||
expect(status.prop("message")).toEqual("Some checks failed");
|
||||
expect(status.prop("type")).toEqual("error");
|
||||
});
|
||||
it('displays a spinner for the overall status until all the checks results are received', () => {
|
||||
it("displays a spinner for the overall status until all the checks results are received", () => {
|
||||
const wrapper = shallow(
|
||||
<OverallStatus
|
||||
releaseInfo={releaseInfo}
|
||||
checkResults={incompleteCheckResults}
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find(Spin).length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('<DisplayStatus />', () => {
|
||||
describe("<DisplayStatus />", () => {
|
||||
const checkDisplayStatus = (status, actionable, label) => {
|
||||
const wrapper = mount(
|
||||
<DisplayStatus
|
||||
|
@ -416,37 +416,37 @@ describe('<DisplayStatus />', () => {
|
|||
actionable={actionable}
|
||||
message="check message"
|
||||
url="check url"
|
||||
/>,
|
||||
/>
|
||||
);
|
||||
const link = wrapper.find('a');
|
||||
expect(link.prop('href')).toEqual('check url');
|
||||
expect(link.prop('title')).toEqual('check message');
|
||||
const link = wrapper.find("a");
|
||||
expect(link.prop("href")).toEqual("check url");
|
||||
expect(link.prop("title")).toEqual("check message");
|
||||
const alert = wrapper.find(Alert);
|
||||
expect(alert.prop('type')).toBe(label);
|
||||
expect(link.text()).toEqual('check message');
|
||||
expect(alert.prop("type")).toBe(label);
|
||||
expect(link.text()).toEqual("check message");
|
||||
};
|
||||
it('displays the status when the status is exists', () => {
|
||||
checkDisplayStatus('exists', true, 'success');
|
||||
it("displays the status when the status is exists", () => {
|
||||
checkDisplayStatus("exists", true, "success");
|
||||
});
|
||||
it('displays the status when the status is incomplete', () => {
|
||||
checkDisplayStatus('incomplete', true, 'warning');
|
||||
it("displays the status when the status is incomplete", () => {
|
||||
checkDisplayStatus("incomplete", true, "warning");
|
||||
});
|
||||
it('displays the status when the status is missing', () => {
|
||||
checkDisplayStatus('missing', true, 'warning');
|
||||
it("displays the status when the status is missing", () => {
|
||||
checkDisplayStatus("missing", true, "warning");
|
||||
});
|
||||
it('displays the error message when there an error', () => {
|
||||
checkDisplayStatus('error', true, 'error');
|
||||
it("displays the error message when there an error", () => {
|
||||
checkDisplayStatus("error", true, "error");
|
||||
});
|
||||
it('displays the status when the status is exists and the item is not actionable', () => {
|
||||
checkDisplayStatus('exists', false, 'success');
|
||||
it("displays the status when the status is exists and the item is not actionable", () => {
|
||||
checkDisplayStatus("exists", false, "success");
|
||||
});
|
||||
it('displays the status when the status is incomplete and the item is not actionable', () => {
|
||||
checkDisplayStatus('incomplete', false, 'info');
|
||||
it("displays the status when the status is incomplete and the item is not actionable", () => {
|
||||
checkDisplayStatus("incomplete", false, "info");
|
||||
});
|
||||
it('displays the status when the status is missing and the item is not actionable', () => {
|
||||
checkDisplayStatus('missing', false, 'info');
|
||||
it("displays the status when the status is missing and the item is not actionable", () => {
|
||||
checkDisplayStatus("missing", false, "info");
|
||||
});
|
||||
it('displays the error message when there an error and the item is not actionable', () => {
|
||||
checkDisplayStatus('error', false, 'error');
|
||||
it("displays the error message when there an error and the item is not actionable", () => {
|
||||
checkDisplayStatus("error", false, "error");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,13 +4,13 @@ import type {
|
|||
CheckResult,
|
||||
ProductVersions,
|
||||
Product,
|
||||
ReleaseInfo,
|
||||
} from './types';
|
||||
ReleaseInfo
|
||||
} from "./types";
|
||||
|
||||
export const SERVER = 'https://pollbot.dev.mozaws.net/v1';
|
||||
export const SERVER = "https://pollbot.dev.mozaws.net/v1";
|
||||
|
||||
export async function getOngoingVersions(
|
||||
product: Product,
|
||||
product: Product
|
||||
): Promise<ProductVersions> {
|
||||
const response = await fetch(`${SERVER}/${product}/ongoing-versions`);
|
||||
return response.json();
|
||||
|
@ -18,7 +18,7 @@ export async function getOngoingVersions(
|
|||
|
||||
export async function getReleaseInfo(
|
||||
product: Product,
|
||||
version: string,
|
||||
version: string
|
||||
): Promise<ReleaseInfo> {
|
||||
const response = await fetch(`${SERVER}/${product}/${version}`);
|
||||
return response.json();
|
||||
|
|
|
@ -4,75 +4,75 @@ import {
|
|||
checkStatus,
|
||||
getPollbotVersion,
|
||||
getOngoingVersions,
|
||||
getReleaseInfo,
|
||||
} from './PollbotAPI';
|
||||
getReleaseInfo
|
||||
} from "./PollbotAPI";
|
||||
|
||||
describe('getOngoingVersions', () => {
|
||||
it('retrieves the list of ongoing versions', async () => {
|
||||
const channelVersions = await getOngoingVersions('firefox');
|
||||
describe("getOngoingVersions", () => {
|
||||
it("retrieves the list of ongoing versions", async () => {
|
||||
const channelVersions = await getOngoingVersions("firefox");
|
||||
expect(channelVersions).toMatchObject({
|
||||
beta: expect.any(String),
|
||||
esr: expect.any(String),
|
||||
nightly: expect.any(String),
|
||||
release: expect.any(String),
|
||||
release: expect.any(String)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getReleaseInfo', () => {
|
||||
it('retrieves the release information for firefox', async () => {
|
||||
const releaseInfo = await getReleaseInfo('firefox', '50.0');
|
||||
describe("getReleaseInfo", () => {
|
||||
it("retrieves the release information for firefox", async () => {
|
||||
const releaseInfo = await getReleaseInfo("firefox", "50.0");
|
||||
expect(releaseInfo).toMatchObject({
|
||||
channel: expect.stringMatching(/nightly|beta|release|esr/),
|
||||
checks: expect.any(Array),
|
||||
product: 'firefox',
|
||||
version: '50.0',
|
||||
product: "firefox",
|
||||
version: "50.0"
|
||||
});
|
||||
releaseInfo.checks.map(check => {
|
||||
expect(check).toMatchObject({
|
||||
title: expect.any(String),
|
||||
url: expect.any(String),
|
||||
url: expect.any(String)
|
||||
});
|
||||
});
|
||||
});
|
||||
it('retrieves the release information for devedition', async () => {
|
||||
const releaseInfo = await getReleaseInfo('devedition', '59.0b3');
|
||||
it("retrieves the release information for devedition", async () => {
|
||||
const releaseInfo = await getReleaseInfo("devedition", "59.0b3");
|
||||
expect(releaseInfo).toMatchObject({
|
||||
channel: expect.stringMatching(/nightly|beta|release|esr|aurora/),
|
||||
checks: expect.any(Array),
|
||||
product: 'devedition',
|
||||
version: '59.0b3',
|
||||
product: "devedition",
|
||||
version: "59.0b3"
|
||||
});
|
||||
releaseInfo.checks.map(check => {
|
||||
expect(check).toMatchObject({
|
||||
title: expect.any(String),
|
||||
url: expect.any(String),
|
||||
url: expect.any(String)
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('checkStatus', () => {
|
||||
it('retrieves the status of a given check', async () => {
|
||||
describe("checkStatus", () => {
|
||||
it("retrieves the status of a given check", async () => {
|
||||
const status = await checkStatus(
|
||||
'https://pollbot.dev.mozaws.net/v1/firefox/50.0/product-details',
|
||||
"https://pollbot.dev.mozaws.net/v1/firefox/50.0/product-details"
|
||||
);
|
||||
expect(status).toEqual({
|
||||
link: 'https://product-details.mozilla.org/1.0/firefox.json',
|
||||
status: 'exists',
|
||||
message: 'We found product-details information about version 50.0',
|
||||
link: "https://product-details.mozilla.org/1.0/firefox.json",
|
||||
status: "exists",
|
||||
message: "We found product-details information about version 50.0"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getPollbotVersion', () => {
|
||||
it('retrieves the version from Pollbot', async () => {
|
||||
describe("getPollbotVersion", () => {
|
||||
it("retrieves the version from Pollbot", async () => {
|
||||
const version = await getPollbotVersion();
|
||||
expect(version).toMatchObject({
|
||||
commit: expect.any(String),
|
||||
name: 'pollbot',
|
||||
name: "pollbot",
|
||||
source: expect.any(String),
|
||||
version: expect.any(String),
|
||||
version: expect.any(String)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,8 +12,8 @@ import {
|
|||
REQUEST_POLLBOT_VERSION,
|
||||
UPDATE_URL,
|
||||
REFRESH_STATUS,
|
||||
REQUEST_STATUS,
|
||||
} from './types';
|
||||
REQUEST_STATUS
|
||||
} from "./types";
|
||||
import type {
|
||||
AddCheckResult,
|
||||
AddServerError,
|
||||
|
@ -31,8 +31,8 @@ import type {
|
|||
UpdateProductVersions,
|
||||
UpdatePollbotVersion,
|
||||
UpdateReleaseInfo,
|
||||
UpdateUrl,
|
||||
} from './types';
|
||||
UpdateUrl
|
||||
} from "./types";
|
||||
|
||||
// Small utility function.
|
||||
export const localUrlFromVersion = ([product, version]: [Product, string]) =>
|
||||
|
@ -43,12 +43,12 @@ export const localUrlFromVersion = ([product, version]: [Product, string]) =>
|
|||
*/
|
||||
|
||||
export function setVersion(product: Product, version: string): SetVersion {
|
||||
return {type: SET_VERSION, product, version};
|
||||
return { type: SET_VERSION, product, version };
|
||||
}
|
||||
|
||||
export const sortByVersion = (a: string, b: string) => {
|
||||
const partsA = a.split('.');
|
||||
const partsB = b.split('.');
|
||||
const partsA = a.split(".");
|
||||
const partsB = b.split(".");
|
||||
if (partsA.length < 2 || partsB.length < 2) {
|
||||
// Bogus version, list it last.
|
||||
return 1;
|
||||
|
@ -93,61 +93,61 @@ export const capitalize = (item: string) =>
|
|||
|
||||
export const capitalizeChannel = ([channel, version]: [string, string]) => [
|
||||
capitalize(channel),
|
||||
version,
|
||||
version
|
||||
];
|
||||
|
||||
export function updateProductVersions(
|
||||
product: Product,
|
||||
versions: VersionsDict,
|
||||
versions: VersionsDict
|
||||
): UpdateProductVersions {
|
||||
return {type: UPDATE_PRODUCT_VERSIONS, product, versions};
|
||||
return { type: UPDATE_PRODUCT_VERSIONS, product, versions };
|
||||
}
|
||||
|
||||
export function updatePollbotVersion(
|
||||
version: APIVersionData,
|
||||
version: APIVersionData
|
||||
): UpdatePollbotVersion {
|
||||
return {type: UPDATE_POLLBOT_VERSION, version};
|
||||
return { type: UPDATE_POLLBOT_VERSION, version };
|
||||
}
|
||||
|
||||
export function updateReleaseInfo(releaseInfo: ReleaseInfo): UpdateReleaseInfo {
|
||||
return {type: UPDATE_RELEASE_INFO, releaseInfo};
|
||||
return { type: UPDATE_RELEASE_INFO, releaseInfo };
|
||||
}
|
||||
|
||||
export function addCheckResult(
|
||||
title: string,
|
||||
result: CheckResult,
|
||||
result: CheckResult
|
||||
): AddCheckResult {
|
||||
return {type: ADD_CHECK_RESULT, title, result};
|
||||
return { type: ADD_CHECK_RESULT, title, result };
|
||||
}
|
||||
|
||||
export function refreshCheckResult(title: string): RefreshCheckResult {
|
||||
return {type: REFRESH_CHECK_RESULT, title};
|
||||
return { type: REFRESH_CHECK_RESULT, title };
|
||||
}
|
||||
|
||||
export function addServerError(title: string, err: string): AddServerError {
|
||||
return {type: ADD_SERVER_ERROR, title, err};
|
||||
return { type: ADD_SERVER_ERROR, title, err };
|
||||
}
|
||||
|
||||
// For sagas
|
||||
export function requestPollbotVersion(): RequestPollbotVersion {
|
||||
return {type: REQUEST_POLLBOT_VERSION};
|
||||
return { type: REQUEST_POLLBOT_VERSION };
|
||||
}
|
||||
|
||||
export function requestOngoingVersions(): RequestOngoingVersions {
|
||||
return {type: REQUEST_ONGOING_VERSIONS};
|
||||
return { type: REQUEST_ONGOING_VERSIONS };
|
||||
}
|
||||
|
||||
export function updateUrl(): UpdateUrl {
|
||||
return {type: UPDATE_URL};
|
||||
return { type: UPDATE_URL };
|
||||
}
|
||||
|
||||
export function refreshStatus(): RefreshStatus {
|
||||
return {type: REFRESH_STATUS};
|
||||
return { type: REFRESH_STATUS };
|
||||
}
|
||||
|
||||
export function requestStatus(
|
||||
product: Product,
|
||||
version: string,
|
||||
version: string
|
||||
): RequestStatus {
|
||||
return {type: REQUEST_STATUS, product, version};
|
||||
return { type: REQUEST_STATUS, product, version };
|
||||
}
|
||||
|
|
|
@ -10,8 +10,8 @@ import {
|
|||
REQUEST_POLLBOT_VERSION,
|
||||
UPDATE_URL,
|
||||
REFRESH_STATUS,
|
||||
REQUEST_STATUS,
|
||||
} from './types';
|
||||
REQUEST_STATUS
|
||||
} from "./types";
|
||||
import {
|
||||
addCheckResult,
|
||||
addServerError,
|
||||
|
@ -26,169 +26,169 @@ import {
|
|||
updateProductVersions,
|
||||
updatePollbotVersion,
|
||||
updateReleaseInfo,
|
||||
updateUrl,
|
||||
} from './actions';
|
||||
updateUrl
|
||||
} from "./actions";
|
||||
|
||||
describe('action creators', () => {
|
||||
it('returns a UPDATE_VERSION_INPUT action for setVersion', () => {
|
||||
expect(setVersion('firefox', '123')).toEqual({
|
||||
describe("action creators", () => {
|
||||
it("returns a UPDATE_VERSION_INPUT action for setVersion", () => {
|
||||
expect(setVersion("firefox", "123")).toEqual({
|
||||
type: SET_VERSION,
|
||||
product: 'firefox',
|
||||
version: '123',
|
||||
product: "firefox",
|
||||
version: "123"
|
||||
});
|
||||
});
|
||||
it('returns a UPDATE_PRODUCT_VERSIONS action for updateProductVersions', () => {
|
||||
it("returns a UPDATE_PRODUCT_VERSIONS action for updateProductVersions", () => {
|
||||
const channelVersions = {
|
||||
nightly: '57.0a1',
|
||||
beta: '56.0b12',
|
||||
release: '55.0.3',
|
||||
esr: '52.3.0esr',
|
||||
nightly: "57.0a1",
|
||||
beta: "56.0b12",
|
||||
release: "55.0.3",
|
||||
esr: "52.3.0esr"
|
||||
};
|
||||
expect(updateProductVersions('firefox', channelVersions)).toEqual({
|
||||
expect(updateProductVersions("firefox", channelVersions)).toEqual({
|
||||
type: UPDATE_PRODUCT_VERSIONS,
|
||||
product: 'firefox',
|
||||
versions: channelVersions,
|
||||
product: "firefox",
|
||||
versions: channelVersions
|
||||
});
|
||||
});
|
||||
it('returns a UPDATE_POLLBOT_VERSION action for updatePollbotVersion', () => {
|
||||
it("returns a UPDATE_POLLBOT_VERSION action for updatePollbotVersion", () => {
|
||||
const pollbotVersion = {
|
||||
name: 'pollbot',
|
||||
source: 'https://github.com/mozilla/PollBot.git',
|
||||
version: '0.2.1-22-g8e09a0f',
|
||||
commit: '8e09a0f8e995344ea24fbb940a6bddc17e0edaed',
|
||||
name: "pollbot",
|
||||
source: "https://github.com/mozilla/PollBot.git",
|
||||
version: "0.2.1-22-g8e09a0f",
|
||||
commit: "8e09a0f8e995344ea24fbb940a6bddc17e0edaed"
|
||||
};
|
||||
expect(updatePollbotVersion(pollbotVersion)).toEqual({
|
||||
type: UPDATE_POLLBOT_VERSION,
|
||||
version: pollbotVersion,
|
||||
version: pollbotVersion
|
||||
});
|
||||
});
|
||||
it('returns a UPDATE_RELEASE_INFO action for updateReleaseInfo', () => {
|
||||
it("returns a UPDATE_RELEASE_INFO action for updateReleaseInfo", () => {
|
||||
const releaseInfo = {
|
||||
product: 'firefox',
|
||||
product: "firefox",
|
||||
checks: [
|
||||
{
|
||||
title: 'Archive Release',
|
||||
url: 'https://pollbot.dev.mozaws.net/v1/firefox/55.0.3/archive',
|
||||
title: "Archive Release",
|
||||
url: "https://pollbot.dev.mozaws.net/v1/firefox/55.0.3/archive"
|
||||
},
|
||||
{
|
||||
title: 'Balrog update rules',
|
||||
url: 'https://pollbot.dev.mozaws.net/v1/firefox/55.0.3/balrog-rules',
|
||||
title: "Balrog update rules",
|
||||
url: "https://pollbot.dev.mozaws.net/v1/firefox/55.0.3/balrog-rules"
|
||||
},
|
||||
{
|
||||
title: 'Download links',
|
||||
title: "Download links",
|
||||
url:
|
||||
'https://pollbot.dev.mozaws.net/v1/firefox/55.0.3/bedrock/download-links',
|
||||
"https://pollbot.dev.mozaws.net/v1/firefox/55.0.3/bedrock/download-links"
|
||||
},
|
||||
{
|
||||
title: 'Product details',
|
||||
title: "Product details",
|
||||
url:
|
||||
'https://pollbot.dev.mozaws.net/v1/firefox/55.0.3/product-details',
|
||||
"https://pollbot.dev.mozaws.net/v1/firefox/55.0.3/product-details"
|
||||
},
|
||||
{
|
||||
title: 'Release notes',
|
||||
title: "Release notes",
|
||||
url:
|
||||
'https://pollbot.dev.mozaws.net/v1/firefox/55.0.3/bedrock/release-notes',
|
||||
"https://pollbot.dev.mozaws.net/v1/firefox/55.0.3/bedrock/release-notes"
|
||||
},
|
||||
{
|
||||
title: 'Security advisories',
|
||||
title: "Security advisories",
|
||||
url:
|
||||
'https://pollbot.dev.mozaws.net/v1/firefox/55.0.3/bedrock/security-advisories',
|
||||
},
|
||||
"https://pollbot.dev.mozaws.net/v1/firefox/55.0.3/bedrock/security-advisories"
|
||||
}
|
||||
],
|
||||
version: '55.0.3',
|
||||
channel: 'release',
|
||||
version: "55.0.3",
|
||||
channel: "release"
|
||||
};
|
||||
expect(updateReleaseInfo(releaseInfo)).toEqual({
|
||||
type: UPDATE_RELEASE_INFO,
|
||||
releaseInfo: releaseInfo,
|
||||
releaseInfo: releaseInfo
|
||||
});
|
||||
});
|
||||
it('returns a ADD_CHECK_RESULT action for addCheckResult', () => {
|
||||
it("returns a ADD_CHECK_RESULT action for addCheckResult", () => {
|
||||
const checkResult = {
|
||||
link: 'https://archive.mozilla.org/pub/firefox/releases/55.0.3/',
|
||||
status: 'exists',
|
||||
link: "https://archive.mozilla.org/pub/firefox/releases/55.0.3/",
|
||||
status: "exists",
|
||||
message:
|
||||
'The archive exists at https://archive.mozilla.org/pub/firefox/releases/55.0.3/ and all 95 locales are present for all platforms (linux-i686, linux-x86_64, mac, win32, win64)',
|
||||
"The archive exists at https://archive.mozilla.org/pub/firefox/releases/55.0.3/ and all 95 locales are present for all platforms (linux-i686, linux-x86_64, mac, win32, win64)"
|
||||
};
|
||||
expect(addCheckResult('some check', checkResult)).toEqual({
|
||||
expect(addCheckResult("some check", checkResult)).toEqual({
|
||||
type: ADD_CHECK_RESULT,
|
||||
title: 'some check',
|
||||
result: checkResult,
|
||||
title: "some check",
|
||||
result: checkResult
|
||||
});
|
||||
});
|
||||
it('returns a REFRESH_CHECK_RESULT action for refreshCheckResult', () => {
|
||||
expect(refreshCheckResult('some check')).toEqual({
|
||||
it("returns a REFRESH_CHECK_RESULT action for refreshCheckResult", () => {
|
||||
expect(refreshCheckResult("some check")).toEqual({
|
||||
type: REFRESH_CHECK_RESULT,
|
||||
title: 'some check',
|
||||
title: "some check"
|
||||
});
|
||||
});
|
||||
it('returns a ADD_SERVER_ERROR action for addServerError', () => {
|
||||
expect(addServerError('some check', 'some error')).toEqual({
|
||||
it("returns a ADD_SERVER_ERROR action for addServerError", () => {
|
||||
expect(addServerError("some check", "some error")).toEqual({
|
||||
type: ADD_SERVER_ERROR,
|
||||
title: 'some check',
|
||||
err: 'some error',
|
||||
title: "some check",
|
||||
err: "some error"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('sagas action creator', () => {
|
||||
it('handles a REQUEST_ONGOING_VERSIONS action for requestOngoingVersions', () => {
|
||||
describe("sagas action creator", () => {
|
||||
it("handles a REQUEST_ONGOING_VERSIONS action for requestOngoingVersions", () => {
|
||||
expect(requestOngoingVersions()).toEqual({
|
||||
type: REQUEST_ONGOING_VERSIONS,
|
||||
type: REQUEST_ONGOING_VERSIONS
|
||||
});
|
||||
});
|
||||
it('handles a REQUEST_POLLBOT_VERSION action for requestPollbotVersion', () => {
|
||||
expect(requestPollbotVersion()).toEqual({type: REQUEST_POLLBOT_VERSION});
|
||||
it("handles a REQUEST_POLLBOT_VERSION action for requestPollbotVersion", () => {
|
||||
expect(requestPollbotVersion()).toEqual({ type: REQUEST_POLLBOT_VERSION });
|
||||
});
|
||||
it('handles a UPDATE_URL action for updateUrl', () => {
|
||||
expect(updateUrl()).toEqual({type: UPDATE_URL});
|
||||
it("handles a UPDATE_URL action for updateUrl", () => {
|
||||
expect(updateUrl()).toEqual({ type: UPDATE_URL });
|
||||
});
|
||||
it('handles a REFRESH_STATUS action for refreshStatus', () => {
|
||||
expect(refreshStatus()).toEqual({type: REFRESH_STATUS});
|
||||
it("handles a REFRESH_STATUS action for refreshStatus", () => {
|
||||
expect(refreshStatus()).toEqual({ type: REFRESH_STATUS });
|
||||
});
|
||||
it('handles a REQUEST_STATUS action for requestStatus', () => {
|
||||
expect(requestStatus('firefox', '50.0')).toEqual({
|
||||
it("handles a REQUEST_STATUS action for requestStatus", () => {
|
||||
expect(requestStatus("firefox", "50.0")).toEqual({
|
||||
type: REQUEST_STATUS,
|
||||
product: 'firefox',
|
||||
version: '50.0',
|
||||
product: "firefox",
|
||||
version: "50.0"
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('sortByVersion helper', () => {
|
||||
it('sorts bogus versions', () => {
|
||||
expect(sortByVersion('0', '56.0')).toEqual(1);
|
||||
describe("sortByVersion helper", () => {
|
||||
it("sorts bogus versions", () => {
|
||||
expect(sortByVersion("0", "56.0")).toEqual(1);
|
||||
});
|
||||
it('sorts equal versions', () => {
|
||||
expect(sortByVersion('56.0', '56.0')).toEqual(0);
|
||||
it("sorts equal versions", () => {
|
||||
expect(sortByVersion("56.0", "56.0")).toEqual(0);
|
||||
});
|
||||
it('sorts similar versions', () => {
|
||||
expect(sortByVersion('56.0', '56.0.1')).toEqual(1);
|
||||
it("sorts similar versions", () => {
|
||||
expect(sortByVersion("56.0", "56.0.1")).toEqual(1);
|
||||
});
|
||||
it('sorts release versions', () => {
|
||||
expect(sortByVersion('56.0', '57.0')).toEqual(1);
|
||||
expect(sortByVersion('56.0.1', '56.0.2')).toEqual(1);
|
||||
it("sorts release versions", () => {
|
||||
expect(sortByVersion("56.0", "57.0")).toEqual(1);
|
||||
expect(sortByVersion("56.0.1", "56.0.2")).toEqual(1);
|
||||
});
|
||||
it('sorts release and beta versions', () => {
|
||||
expect(sortByVersion('56.0b1', '56.0')).toEqual(1);
|
||||
expect(sortByVersion('56.0', '56.0b1')).toEqual(-1);
|
||||
it("sorts release and beta versions", () => {
|
||||
expect(sortByVersion("56.0b1", "56.0")).toEqual(1);
|
||||
expect(sortByVersion("56.0", "56.0b1")).toEqual(-1);
|
||||
});
|
||||
it('sorts alpha and beta versions', () => {
|
||||
expect(sortByVersion('56.0a1', '56.0b1')).toEqual(1);
|
||||
it("sorts alpha and beta versions", () => {
|
||||
expect(sortByVersion("56.0a1", "56.0b1")).toEqual(1);
|
||||
});
|
||||
it('sorts beta versions', () => {
|
||||
expect(sortByVersion('56.0b1', '56.0b2')).toEqual(1);
|
||||
it("sorts beta versions", () => {
|
||||
expect(sortByVersion("56.0b1", "56.0b2")).toEqual(1);
|
||||
});
|
||||
it('sorts bogus sub versions', () => {
|
||||
expect(sortByVersion('56.0', '56.a')).toEqual(1);
|
||||
it("sorts bogus sub versions", () => {
|
||||
expect(sortByVersion("56.0", "56.a")).toEqual(1);
|
||||
});
|
||||
it('sorts random versions', () => {
|
||||
expect(sortByVersion('55.0.3', '57.0b3')).toBeGreaterThan(0);
|
||||
it("sorts random versions", () => {
|
||||
expect(sortByVersion("55.0.3", "57.0b3")).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('capitalizeChannel helper', () => {
|
||||
it('uppercases the first letter of the channel', () => {
|
||||
expect(capitalizeChannel(['foo', 'bar'])).toEqual(['Foo', 'bar']);
|
||||
describe("capitalizeChannel helper", () => {
|
||||
it("uppercases the first letter of the channel", () => {
|
||||
expect(capitalizeChannel(["foo", "bar"])).toEqual(["Foo", "bar"]);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
// @flow
|
||||
|
||||
import {createStore, applyMiddleware, compose} from 'redux';
|
||||
import {deliveryDashboard} from './reducers';
|
||||
import createSagaMiddleware from 'redux-saga';
|
||||
import thunkMiddleware from 'redux-thunk';
|
||||
import {createLogger} from 'redux-logger';
|
||||
import type {Store} from './types';
|
||||
import {rootSaga} from './sagas';
|
||||
import { createStore, applyMiddleware, compose } from "redux";
|
||||
import { deliveryDashboard } from "./reducers";
|
||||
import createSagaMiddleware from "redux-saga";
|
||||
import thunkMiddleware from "redux-thunk";
|
||||
import { createLogger } from "redux-logger";
|
||||
import type { Store } from "./types";
|
||||
import { rootSaga } from "./sagas";
|
||||
|
||||
/**
|
||||
* Isolate the store creation into a function, so that it can be used outside of the
|
||||
|
@ -27,9 +27,9 @@ export default function initializeStore(): Store {
|
|||
applyMiddleware(
|
||||
sagaMiddleware,
|
||||
thunkMiddleware, // lets us dispatch() functions
|
||||
loggerMiddleware, // neat middleware that logs actions
|
||||
),
|
||||
),
|
||||
loggerMiddleware // neat middleware that logs actions
|
||||
)
|
||||
)
|
||||
);
|
||||
sagaMiddleware.run(rootSaga);
|
||||
|
||||
|
|
16
src/index.js
16
src/index.js
|
@ -1,19 +1,19 @@
|
|||
// @flow
|
||||
import ConnectedApp from './App';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import registerServiceWorker from './registerServiceWorker';
|
||||
import {Provider} from 'react-redux';
|
||||
import createStore from './create-store';
|
||||
import ConnectedApp from "./App";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import registerServiceWorker from "./registerServiceWorker";
|
||||
import { Provider } from "react-redux";
|
||||
import createStore from "./create-store";
|
||||
|
||||
const root = document && document.getElementById('root');
|
||||
const root = document && document.getElementById("root");
|
||||
|
||||
if (root) {
|
||||
ReactDOM.render(
|
||||
<Provider store={createStore()}>
|
||||
<ConnectedApp />
|
||||
</Provider>,
|
||||
root,
|
||||
root
|
||||
);
|
||||
registerServiceWorker();
|
||||
}
|
||||
|
|
|
@ -7,23 +7,23 @@ import {
|
|||
SET_VERSION,
|
||||
UPDATE_PRODUCT_VERSIONS,
|
||||
UPDATE_POLLBOT_VERSION,
|
||||
UPDATE_RELEASE_INFO,
|
||||
} from './types';
|
||||
import type {Action, State} from './types';
|
||||
UPDATE_RELEASE_INFO
|
||||
} from "./types";
|
||||
import type { Action, State } from "./types";
|
||||
|
||||
export const initialState: State = {
|
||||
version: ['firefox', ''],
|
||||
productVersions: {firefox: {}, devedition: {}},
|
||||
version: ["firefox", ""],
|
||||
productVersions: { firefox: {}, devedition: {} },
|
||||
releaseInfo: null,
|
||||
checkResults: {},
|
||||
pollbotVersion: null,
|
||||
shouldRefresh: false,
|
||||
errors: [],
|
||||
errors: []
|
||||
};
|
||||
|
||||
export function deliveryDashboard(
|
||||
state: State = initialState,
|
||||
action: Action,
|
||||
action: Action
|
||||
): State {
|
||||
let errors;
|
||||
let updatedCheckResults;
|
||||
|
@ -31,44 +31,44 @@ export function deliveryDashboard(
|
|||
case ADD_CHECK_RESULT:
|
||||
return Object.assign({}, state, {
|
||||
checkResults: Object.assign({}, state.checkResults, {
|
||||
[action.title]: action.result,
|
||||
[action.title]: action.result
|
||||
}),
|
||||
shouldRefresh:
|
||||
action.result.status !== 'exists' ? true : state.shouldRefresh,
|
||||
action.result.status !== "exists" ? true : state.shouldRefresh
|
||||
});
|
||||
case REFRESH_CHECK_RESULT:
|
||||
updatedCheckResults = Object.assign({}, state.checkResults);
|
||||
delete updatedCheckResults[action.title];
|
||||
return Object.assign({}, state, {
|
||||
checkResults: updatedCheckResults,
|
||||
checkResults: updatedCheckResults
|
||||
});
|
||||
case ADD_SERVER_ERROR:
|
||||
errors = state.errors.slice();
|
||||
errors.push([action.title, action.err]);
|
||||
return Object.assign({}, state, {
|
||||
errors: errors,
|
||||
shouldRefresh: true,
|
||||
shouldRefresh: true
|
||||
});
|
||||
case SET_VERSION:
|
||||
return Object.assign({}, state, {
|
||||
version: [action.product, action.version],
|
||||
checkResults: {},
|
||||
shouldRefresh: false,
|
||||
errors: [],
|
||||
errors: []
|
||||
});
|
||||
case UPDATE_PRODUCT_VERSIONS:
|
||||
return Object.assign({}, state, {
|
||||
productVersions: Object.assign({}, state.productVersions, {
|
||||
[action.product]: action.versions,
|
||||
}),
|
||||
[action.product]: action.versions
|
||||
})
|
||||
});
|
||||
case UPDATE_RELEASE_INFO:
|
||||
return Object.assign({}, state, {
|
||||
releaseInfo: action.releaseInfo,
|
||||
releaseInfo: action.releaseInfo
|
||||
});
|
||||
case UPDATE_POLLBOT_VERSION:
|
||||
return Object.assign({}, state, {
|
||||
pollbotVersion: action.version,
|
||||
pollbotVersion: action.version
|
||||
});
|
||||
default:
|
||||
return state;
|
||||
|
|
|
@ -5,263 +5,267 @@ import {
|
|||
SET_VERSION,
|
||||
UPDATE_PRODUCT_VERSIONS,
|
||||
UPDATE_POLLBOT_VERSION,
|
||||
UPDATE_RELEASE_INFO,
|
||||
} from './types';
|
||||
import {deliveryDashboard, initialState} from './reducers';
|
||||
UPDATE_RELEASE_INFO
|
||||
} from "./types";
|
||||
import { deliveryDashboard, initialState } from "./reducers";
|
||||
|
||||
const stateWith = stateCrumbs => Object.assign({}, initialState, stateCrumbs);
|
||||
|
||||
describe('deliveryDashboard reducer', () => {
|
||||
it('returns the initial state', () => {
|
||||
describe("deliveryDashboard reducer", () => {
|
||||
it("returns the initial state", () => {
|
||||
expect(deliveryDashboard(undefined, {})).toEqual(initialState);
|
||||
});
|
||||
it('handles ADD_CHECK_RESULT', () => {
|
||||
it("handles ADD_CHECK_RESULT", () => {
|
||||
const checkResult = {
|
||||
status: 'exists',
|
||||
message: 'successful test',
|
||||
link: 'some url',
|
||||
status: "exists",
|
||||
message: "successful test",
|
||||
link: "some url"
|
||||
};
|
||||
expect(
|
||||
deliveryDashboard(undefined, {
|
||||
type: ADD_CHECK_RESULT,
|
||||
title: 'some test',
|
||||
result: checkResult,
|
||||
}),
|
||||
title: "some test",
|
||||
result: checkResult
|
||||
})
|
||||
).toEqual(
|
||||
stateWith({
|
||||
checkResults: {
|
||||
'some test': checkResult,
|
||||
"some test": checkResult
|
||||
},
|
||||
shouldRefresh: false,
|
||||
}),
|
||||
shouldRefresh: false
|
||||
})
|
||||
);
|
||||
|
||||
const otherCheckResult = {
|
||||
status: 'exists',
|
||||
message: 'successful test',
|
||||
link: 'some url',
|
||||
status: "exists",
|
||||
message: "successful test",
|
||||
link: "some url"
|
||||
};
|
||||
expect(
|
||||
deliveryDashboard(
|
||||
stateWith({
|
||||
checkResults: {
|
||||
'some test': checkResult,
|
||||
},
|
||||
"some test": checkResult
|
||||
}
|
||||
}),
|
||||
{
|
||||
type: ADD_CHECK_RESULT,
|
||||
title: 'some other test',
|
||||
result: otherCheckResult,
|
||||
},
|
||||
),
|
||||
title: "some other test",
|
||||
result: otherCheckResult
|
||||
}
|
||||
)
|
||||
).toEqual(
|
||||
stateWith({
|
||||
checkResults: {
|
||||
'some test': checkResult,
|
||||
'some other test': otherCheckResult,
|
||||
"some test": checkResult,
|
||||
"some other test": otherCheckResult
|
||||
},
|
||||
shouldRefresh: false,
|
||||
}),
|
||||
shouldRefresh: false
|
||||
})
|
||||
);
|
||||
|
||||
const failingCheckResult = {
|
||||
status: 'incomplete',
|
||||
message: 'successful test',
|
||||
link: 'some url',
|
||||
status: "incomplete",
|
||||
message: "successful test",
|
||||
link: "some url"
|
||||
};
|
||||
expect(
|
||||
deliveryDashboard(
|
||||
stateWith({
|
||||
checkResults: {
|
||||
'some test': checkResult,
|
||||
},
|
||||
"some test": checkResult
|
||||
}
|
||||
}),
|
||||
{
|
||||
type: ADD_CHECK_RESULT,
|
||||
title: 'some other test',
|
||||
result: failingCheckResult,
|
||||
},
|
||||
),
|
||||
title: "some other test",
|
||||
result: failingCheckResult
|
||||
}
|
||||
)
|
||||
).toEqual(
|
||||
stateWith({
|
||||
checkResults: {
|
||||
'some test': checkResult,
|
||||
'some other test': failingCheckResult,
|
||||
"some test": checkResult,
|
||||
"some other test": failingCheckResult
|
||||
},
|
||||
shouldRefresh: true,
|
||||
}),
|
||||
shouldRefresh: true
|
||||
})
|
||||
);
|
||||
});
|
||||
it('handles REFRESH_CHECK_RESULT', () => {
|
||||
it("handles REFRESH_CHECK_RESULT", () => {
|
||||
const checkResult = {
|
||||
status: 'exists',
|
||||
message: 'successful test',
|
||||
link: 'some url',
|
||||
status: "exists",
|
||||
message: "successful test",
|
||||
link: "some url"
|
||||
};
|
||||
expect(
|
||||
deliveryDashboard(undefined, {
|
||||
type: REFRESH_CHECK_RESULT,
|
||||
title: 'some test',
|
||||
}),
|
||||
title: "some test"
|
||||
})
|
||||
).toEqual(
|
||||
stateWith({
|
||||
checkResults: {},
|
||||
}),
|
||||
checkResults: {}
|
||||
})
|
||||
);
|
||||
|
||||
const failingCheckResult = {
|
||||
status: 'incomplete',
|
||||
message: 'successful test',
|
||||
link: 'some url',
|
||||
status: "incomplete",
|
||||
message: "successful test",
|
||||
link: "some url"
|
||||
};
|
||||
expect(
|
||||
deliveryDashboard(
|
||||
stateWith({
|
||||
checkResults: {
|
||||
'some test': checkResult,
|
||||
'some other test': failingCheckResult,
|
||||
},
|
||||
"some test": checkResult,
|
||||
"some other test": failingCheckResult
|
||||
}
|
||||
}),
|
||||
{
|
||||
type: REFRESH_CHECK_RESULT,
|
||||
title: 'some other test',
|
||||
result: failingCheckResult,
|
||||
},
|
||||
),
|
||||
title: "some other test",
|
||||
result: failingCheckResult
|
||||
}
|
||||
)
|
||||
).toEqual(
|
||||
stateWith({
|
||||
checkResults: {
|
||||
'some test': checkResult,
|
||||
},
|
||||
}),
|
||||
"some test": checkResult
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
it('handles ADD_SERVER_ERROR', () => {
|
||||
it("handles ADD_SERVER_ERROR", () => {
|
||||
expect(
|
||||
deliveryDashboard(undefined, {
|
||||
type: ADD_SERVER_ERROR,
|
||||
title: 'some check',
|
||||
err: 'some error',
|
||||
}),
|
||||
title: "some check",
|
||||
err: "some error"
|
||||
})
|
||||
).toEqual(
|
||||
stateWith({errors: [['some check', 'some error']], shouldRefresh: true}),
|
||||
stateWith({ errors: [["some check", "some error"]], shouldRefresh: true })
|
||||
);
|
||||
expect(
|
||||
deliveryDashboard(
|
||||
stateWith({
|
||||
errors: [['some check', 'some error']],
|
||||
errors: [["some check", "some error"]]
|
||||
}),
|
||||
{
|
||||
type: ADD_SERVER_ERROR,
|
||||
title: 'some other check',
|
||||
err: 'some other error',
|
||||
},
|
||||
),
|
||||
title: "some other check",
|
||||
err: "some other error"
|
||||
}
|
||||
)
|
||||
).toEqual(
|
||||
stateWith({
|
||||
errors: [
|
||||
['some check', 'some error'],
|
||||
['some other check', 'some other error'],
|
||||
["some check", "some error"],
|
||||
["some other check", "some other error"]
|
||||
],
|
||||
shouldRefresh: true,
|
||||
}),
|
||||
shouldRefresh: true
|
||||
})
|
||||
);
|
||||
});
|
||||
it('handles SET_VERSION', () => {
|
||||
it("handles SET_VERSION", () => {
|
||||
expect(
|
||||
deliveryDashboard(undefined, {
|
||||
type: SET_VERSION,
|
||||
product: 'firefox',
|
||||
version: '50.0',
|
||||
}),
|
||||
).toEqual(stateWith({version: ['firefox', '50.0'], shouldRefresh: false}));
|
||||
product: "firefox",
|
||||
version: "50.0"
|
||||
})
|
||||
).toEqual(
|
||||
stateWith({ version: ["firefox", "50.0"], shouldRefresh: false })
|
||||
);
|
||||
expect(
|
||||
deliveryDashboard(
|
||||
stateWith({
|
||||
version: ['firefox', '50.0'],
|
||||
version: ["firefox", "50.0"]
|
||||
}),
|
||||
{
|
||||
type: SET_VERSION,
|
||||
product: 'firefox',
|
||||
version: '51.0',
|
||||
},
|
||||
),
|
||||
).toEqual(stateWith({version: ['firefox', '51.0'], shouldRefresh: false}));
|
||||
product: "firefox",
|
||||
version: "51.0"
|
||||
}
|
||||
)
|
||||
).toEqual(
|
||||
stateWith({ version: ["firefox", "51.0"], shouldRefresh: false })
|
||||
);
|
||||
});
|
||||
it('handles UPDATE_PRODUCT_VERSIONS', () => {
|
||||
it("handles UPDATE_PRODUCT_VERSIONS", () => {
|
||||
expect(
|
||||
deliveryDashboard(undefined, {
|
||||
type: UPDATE_PRODUCT_VERSIONS,
|
||||
product: 'firefox',
|
||||
versions: {release: '0.1.2'},
|
||||
}),
|
||||
product: "firefox",
|
||||
versions: { release: "0.1.2" }
|
||||
})
|
||||
).toEqual(
|
||||
stateWith({
|
||||
productVersions: {
|
||||
firefox: {release: '0.1.2'},
|
||||
devedition: {},
|
||||
},
|
||||
}),
|
||||
firefox: { release: "0.1.2" },
|
||||
devedition: {}
|
||||
}
|
||||
})
|
||||
);
|
||||
expect(
|
||||
deliveryDashboard(
|
||||
stateWith({
|
||||
productVersions: {
|
||||
firefox: {release: '0.1.2'},
|
||||
devedition: {},
|
||||
},
|
||||
firefox: { release: "0.1.2" },
|
||||
devedition: {}
|
||||
}
|
||||
}),
|
||||
{
|
||||
type: UPDATE_PRODUCT_VERSIONS,
|
||||
product: 'firefox',
|
||||
versions: {nightly: '1.2.3', release: '0.1.3'},
|
||||
},
|
||||
),
|
||||
product: "firefox",
|
||||
versions: { nightly: "1.2.3", release: "0.1.3" }
|
||||
}
|
||||
)
|
||||
).toEqual(
|
||||
stateWith({
|
||||
productVersions: {
|
||||
firefox: {nightly: '1.2.3', release: '0.1.3'},
|
||||
devedition: {},
|
||||
},
|
||||
}),
|
||||
firefox: { nightly: "1.2.3", release: "0.1.3" },
|
||||
devedition: {}
|
||||
}
|
||||
})
|
||||
);
|
||||
});
|
||||
it('handles UPDATE_RELEASE_INFO', () => {
|
||||
it("handles UPDATE_RELEASE_INFO", () => {
|
||||
expect(
|
||||
deliveryDashboard(undefined, {
|
||||
type: UPDATE_RELEASE_INFO,
|
||||
releaseInfo: 'some new release info',
|
||||
}),
|
||||
).toEqual(stateWith({releaseInfo: 'some new release info'}));
|
||||
releaseInfo: "some new release info"
|
||||
})
|
||||
).toEqual(stateWith({ releaseInfo: "some new release info" }));
|
||||
expect(
|
||||
deliveryDashboard(
|
||||
stateWith({
|
||||
releaseInfo: 'some release info',
|
||||
releaseInfo: "some release info"
|
||||
}),
|
||||
{
|
||||
type: UPDATE_RELEASE_INFO,
|
||||
releaseInfo: 'some new release info',
|
||||
},
|
||||
),
|
||||
).toEqual(stateWith({releaseInfo: 'some new release info'}));
|
||||
releaseInfo: "some new release info"
|
||||
}
|
||||
)
|
||||
).toEqual(stateWith({ releaseInfo: "some new release info" }));
|
||||
});
|
||||
it('handles UPDATE_POLLBOT_VERSION', () => {
|
||||
it("handles UPDATE_POLLBOT_VERSION", () => {
|
||||
expect(
|
||||
deliveryDashboard(undefined, {
|
||||
type: UPDATE_POLLBOT_VERSION,
|
||||
version: 'some new pollbot version',
|
||||
}),
|
||||
).toEqual(stateWith({pollbotVersion: 'some new pollbot version'}));
|
||||
version: "some new pollbot version"
|
||||
})
|
||||
).toEqual(stateWith({ pollbotVersion: "some new pollbot version" }));
|
||||
expect(
|
||||
deliveryDashboard(
|
||||
stateWith({
|
||||
pollbotVersion: 'some pollbot version',
|
||||
pollbotVersion: "some pollbot version"
|
||||
}),
|
||||
{
|
||||
type: UPDATE_POLLBOT_VERSION,
|
||||
version: 'some new pollbot version',
|
||||
},
|
||||
),
|
||||
).toEqual(stateWith({pollbotVersion: 'some new pollbot version'}));
|
||||
version: "some new pollbot version"
|
||||
}
|
||||
)
|
||||
).toEqual(stateWith({ pollbotVersion: "some new pollbot version" }));
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,26 +10,26 @@
|
|||
// This link also includes instructions on opting out of this behavior.
|
||||
|
||||
const isLocalhost: boolean = Boolean(
|
||||
window.location.hostname === 'localhost' ||
|
||||
window.location.hostname === "localhost" ||
|
||||
// [::1] is the IPv6 localhost address.
|
||||
window.location.hostname === '[::1]' ||
|
||||
window.location.hostname === "[::1]" ||
|
||||
// 127.0.0.1/8 is considered localhost for IPv4.
|
||||
window.location.hostname.match(
|
||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/,
|
||||
),
|
||||
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
|
||||
)
|
||||
);
|
||||
|
||||
export default function register() {
|
||||
if (
|
||||
process.env.NODE_ENV === 'production' &&
|
||||
'serviceWorker' in navigator &&
|
||||
process.env.NODE_ENV === "production" &&
|
||||
"serviceWorker" in navigator &&
|
||||
process.env.PUBLIC_URL &&
|
||||
navigator.serviceWorker
|
||||
) {
|
||||
// The URL constructor is available in all browsers that support SW.
|
||||
const publicUrl = new URL(
|
||||
process.env.PUBLIC_URL,
|
||||
window.location.toString(),
|
||||
window.location.toString()
|
||||
);
|
||||
if (publicUrl.origin !== window.location.origin) {
|
||||
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||
|
@ -38,7 +38,7 @@ export default function register() {
|
|||
return;
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
window.addEventListener("load", () => {
|
||||
if (process.env.PUBLIC_URL) {
|
||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||
|
||||
|
@ -62,7 +62,7 @@ function registerValidSW(swUrl) {
|
|||
registration.onupdatefound = () => {
|
||||
const installingWorker = registration.installing;
|
||||
installingWorker.onstatechange = () => {
|
||||
if (installingWorker.state === 'installed') {
|
||||
if (installingWorker.state === "installed") {
|
||||
if (
|
||||
navigator.serviceWorker &&
|
||||
navigator.serviceWorker.controller
|
||||
|
@ -71,19 +71,19 @@ function registerValidSW(swUrl) {
|
|||
// the fresh content will have been added to the cache.
|
||||
// It's the perfect time to display a "New content is
|
||||
// available; please refresh." message in your web app.
|
||||
console.log('New content is available; please refresh.');
|
||||
console.log("New content is available; please refresh.");
|
||||
} else {
|
||||
// At this point, everything has been precached.
|
||||
// It's the perfect time to display a
|
||||
// "Content is cached for offline use." message.
|
||||
console.log('Content is cached for offline use.');
|
||||
console.log("Content is cached for offline use.");
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error during service worker registration:', error);
|
||||
console.error("Error during service worker registration:", error);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -94,7 +94,7 @@ function checkValidServiceWorker(swUrl) {
|
|||
// Ensure service worker exists, and that we really are getting a JS file.
|
||||
if (
|
||||
response.status === 404 ||
|
||||
response.headers.get('content-type').indexOf('javascript') === -1
|
||||
response.headers.get("content-type").indexOf("javascript") === -1
|
||||
) {
|
||||
// No service worker found. Probably a different app. Reload the page.
|
||||
navigator.serviceWorker &&
|
||||
|
@ -110,13 +110,13 @@ function checkValidServiceWorker(swUrl) {
|
|||
})
|
||||
.catch(() => {
|
||||
console.log(
|
||||
'No internet connection found. App is running in offline mode.',
|
||||
"No internet connection found. App is running in offline mode."
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function unregister() {
|
||||
if ('serviceWorker' in navigator && navigator.serviceWorker) {
|
||||
if ("serviceWorker" in navigator && navigator.serviceWorker) {
|
||||
navigator.serviceWorker.ready.then(registration => {
|
||||
registration.unregister();
|
||||
});
|
||||
|
|
54
src/sagas.js
54
src/sagas.js
|
@ -6,8 +6,8 @@ import {
|
|||
UPDATE_URL,
|
||||
REFRESH_STATUS,
|
||||
REQUEST_STATUS,
|
||||
products,
|
||||
} from './types';
|
||||
products
|
||||
} from "./types";
|
||||
import type {
|
||||
APIVersionData,
|
||||
CheckResult,
|
||||
|
@ -15,15 +15,15 @@ import type {
|
|||
Product,
|
||||
ReleaseInfo,
|
||||
RequestStatus,
|
||||
State,
|
||||
} from './types';
|
||||
import {all, call, put, select, takeEvery} from 'redux-saga/effects';
|
||||
State
|
||||
} from "./types";
|
||||
import { all, call, put, select, takeEvery } from "redux-saga/effects";
|
||||
import {
|
||||
checkStatus,
|
||||
getOngoingVersions,
|
||||
getPollbotVersion,
|
||||
getReleaseInfo,
|
||||
} from './PollbotAPI';
|
||||
getReleaseInfo
|
||||
} from "./PollbotAPI";
|
||||
import {
|
||||
addCheckResult,
|
||||
addServerError,
|
||||
|
@ -32,8 +32,8 @@ import {
|
|||
setVersion,
|
||||
updateProductVersions,
|
||||
updatePollbotVersion,
|
||||
updateReleaseInfo,
|
||||
} from './actions';
|
||||
updateReleaseInfo
|
||||
} from "./actions";
|
||||
|
||||
type Saga = Generator<*, void, *>;
|
||||
|
||||
|
@ -43,7 +43,7 @@ export function* fetchPollbotVersion(): Saga {
|
|||
const version: APIVersionData = yield call(getPollbotVersion);
|
||||
yield put(updatePollbotVersion(version));
|
||||
} catch (err) {
|
||||
console.error('Failed getting the pollbot version', err);
|
||||
console.error("Failed getting the pollbot version", err);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,8 +53,8 @@ export function* fetchAndUpdateVersions(product: Product): Saga {
|
|||
yield put(updateProductVersions(product, versions));
|
||||
} catch (err) {
|
||||
console.error(
|
||||
'Failed getting the latest channel versions for product: ' + product,
|
||||
err,
|
||||
"Failed getting the latest channel versions for product: " + product,
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -73,10 +73,10 @@ export function* updateUrl(): Saga {
|
|||
export function* checkResultAndUpdateAndNotify(
|
||||
title: string,
|
||||
url: string,
|
||||
prevResult: CheckResult,
|
||||
prevResult: CheckResult
|
||||
): Saga {
|
||||
const notifyChanges = (checkTitle, status) => {
|
||||
if (Notification.permission === 'granted') {
|
||||
if (Notification.permission === "granted") {
|
||||
new Notification(`${checkTitle}: status changed (${status}).`);
|
||||
}
|
||||
};
|
||||
|
@ -100,10 +100,10 @@ export function* refreshStatus(): Saga {
|
|||
yield all(
|
||||
state.releaseInfo.checks
|
||||
// only refresh checks that were failing.
|
||||
.filter(({title}) => state.checkResults[title].status !== 'exists')
|
||||
.map(({url, title}) =>
|
||||
call(checkResultAndUpdateAndNotify, title, url, prevResults[title]),
|
||||
),
|
||||
.filter(({ title }) => state.checkResults[title].status !== "exists")
|
||||
.map(({ url, title }) =>
|
||||
call(checkResultAndUpdateAndNotify, title, url, prevResults[title])
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -120,8 +120,8 @@ export function* checkResultAndUpdate(title: string, url: string): Saga {
|
|||
|
||||
// Requesting a status for a new version.
|
||||
export function* requestStatus(action: RequestStatus): Saga {
|
||||
let {product, version} = action;
|
||||
let {productVersions} = yield select();
|
||||
let { product, version } = action;
|
||||
let { productVersions } = yield select();
|
||||
try {
|
||||
if (
|
||||
Object.keys(productVersions).length === 0 ||
|
||||
|
@ -132,7 +132,7 @@ export function* requestStatus(action: RequestStatus): Saga {
|
|||
const versions = yield call(getOngoingVersions, product);
|
||||
yield put(updateProductVersions(product, versions));
|
||||
// We now have the product channel versions.
|
||||
({productVersions} = yield select());
|
||||
({ productVersions } = yield select());
|
||||
}
|
||||
if (productVersions[product].hasOwnProperty(version)) {
|
||||
version = productVersions[product][version];
|
||||
|
@ -142,18 +142,18 @@ export function* requestStatus(action: RequestStatus): Saga {
|
|||
const releaseInfo: ReleaseInfo = yield call(
|
||||
getReleaseInfo,
|
||||
product,
|
||||
version,
|
||||
version
|
||||
);
|
||||
yield put(updateReleaseInfo(releaseInfo));
|
||||
yield all(
|
||||
releaseInfo.checks.map(({url, title}) =>
|
||||
call(checkResultAndUpdate, title, url),
|
||||
),
|
||||
releaseInfo.checks.map(({ url, title }) =>
|
||||
call(checkResultAndUpdate, title, url)
|
||||
)
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(
|
||||
`Failed getting the release info for ${product} ${version}`,
|
||||
err,
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -165,6 +165,6 @@ export function* rootSaga(): Saga {
|
|||
takeEvery(REQUEST_POLLBOT_VERSION, fetchPollbotVersion),
|
||||
takeEvery(UPDATE_URL, updateUrl),
|
||||
takeEvery(REFRESH_STATUS, refreshStatus),
|
||||
takeEvery(REQUEST_STATUS, requestStatus),
|
||||
takeEvery(REQUEST_STATUS, requestStatus)
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import {all, call, put, select, takeEvery} from 'redux-saga/effects';
|
||||
import {cloneableGenerator} from 'redux-saga/utils';
|
||||
import { all, call, put, select, takeEvery } from "redux-saga/effects";
|
||||
import { cloneableGenerator } from "redux-saga/utils";
|
||||
import {
|
||||
checkStatus,
|
||||
getOngoingVersions,
|
||||
getPollbotVersion,
|
||||
getReleaseInfo,
|
||||
} from './PollbotAPI';
|
||||
getReleaseInfo
|
||||
} from "./PollbotAPI";
|
||||
import {
|
||||
addCheckResult,
|
||||
addServerError,
|
||||
|
@ -13,15 +13,15 @@ import {
|
|||
setVersion,
|
||||
updateProductVersions,
|
||||
updatePollbotVersion,
|
||||
updateReleaseInfo,
|
||||
} from './actions';
|
||||
updateReleaseInfo
|
||||
} from "./actions";
|
||||
import {
|
||||
REFRESH_STATUS,
|
||||
REQUEST_ONGOING_VERSIONS,
|
||||
REQUEST_POLLBOT_VERSION,
|
||||
REQUEST_STATUS,
|
||||
UPDATE_URL,
|
||||
} from './types';
|
||||
UPDATE_URL
|
||||
} from "./types";
|
||||
import {
|
||||
checkResultAndUpdate,
|
||||
checkResultAndUpdateAndNotify,
|
||||
|
@ -31,19 +31,19 @@ import {
|
|||
refreshStatus,
|
||||
requestStatus,
|
||||
rootSaga,
|
||||
updateUrl,
|
||||
} from './sagas';
|
||||
updateUrl
|
||||
} from "./sagas";
|
||||
|
||||
describe('sagas', () => {
|
||||
it('handles fetchPollbotVersion', () => {
|
||||
describe("sagas", () => {
|
||||
it("handles fetchPollbotVersion", () => {
|
||||
const data = {};
|
||||
data.saga = cloneableGenerator(fetchPollbotVersion)();
|
||||
|
||||
const pollbotVersion = {
|
||||
name: 'pollbot',
|
||||
source: 'https://github.com/mozilla/PollBot.git',
|
||||
version: '0.2.1-22-g8e09a0f',
|
||||
commit: '8e09a0f8e995344ea24fbb940a6bddc17e0edaed',
|
||||
name: "pollbot",
|
||||
source: "https://github.com/mozilla/PollBot.git",
|
||||
version: "0.2.1-22-g8e09a0f",
|
||||
commit: "8e09a0f8e995344ea24fbb940a6bddc17e0edaed"
|
||||
};
|
||||
expect(data.saga.next().value).toEqual(call(getPollbotVersion));
|
||||
|
||||
|
@ -51,99 +51,99 @@ describe('sagas', () => {
|
|||
data.sagaThrow = data.saga.clone();
|
||||
|
||||
expect(data.saga.next(pollbotVersion).value).toEqual(
|
||||
put(updatePollbotVersion(pollbotVersion)),
|
||||
put(updatePollbotVersion(pollbotVersion))
|
||||
);
|
||||
expect(data.saga.next().done).toBe(true);
|
||||
|
||||
console.error = jest.fn();
|
||||
data.sagaThrow.throw('error');
|
||||
data.sagaThrow.throw("error");
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
'Failed getting the pollbot version',
|
||||
'error',
|
||||
"Failed getting the pollbot version",
|
||||
"error"
|
||||
);
|
||||
expect(data.sagaThrow.next().done).toBe(true);
|
||||
});
|
||||
|
||||
it('handles fetchOngoingVersions', () => {
|
||||
it("handles fetchOngoingVersions", () => {
|
||||
const data = {};
|
||||
data.saga = cloneableGenerator(fetchOngoingVersions)();
|
||||
|
||||
expect(data.saga.next().value).toEqual(
|
||||
all([
|
||||
call(fetchAndUpdateVersions, 'firefox'),
|
||||
call(fetchAndUpdateVersions, 'devedition'),
|
||||
]),
|
||||
call(fetchAndUpdateVersions, "firefox"),
|
||||
call(fetchAndUpdateVersions, "devedition")
|
||||
])
|
||||
);
|
||||
expect(data.saga.next().done).toBe(true);
|
||||
});
|
||||
|
||||
it('handles fetchAndUpdateVersions', () => {
|
||||
it("handles fetchAndUpdateVersions", () => {
|
||||
const data = {};
|
||||
data.saga = cloneableGenerator(fetchAndUpdateVersions)('firefox');
|
||||
data.saga = cloneableGenerator(fetchAndUpdateVersions)("firefox");
|
||||
|
||||
const channelVersions = {
|
||||
nightly: '57.0a1',
|
||||
beta: '56.0b12',
|
||||
release: '55.0.3',
|
||||
esr: '52.3.0esr',
|
||||
nightly: "57.0a1",
|
||||
beta: "56.0b12",
|
||||
release: "55.0.3",
|
||||
esr: "52.3.0esr"
|
||||
};
|
||||
expect(data.saga.next().value).toEqual(call(getOngoingVersions, 'firefox'));
|
||||
expect(data.saga.next().value).toEqual(call(getOngoingVersions, "firefox"));
|
||||
|
||||
// Clone to test success and failure of getOngoingVersions.
|
||||
data.sagaThrow = data.saga.clone();
|
||||
|
||||
expect(data.saga.next(channelVersions).value).toEqual(
|
||||
put(updateProductVersions('firefox', channelVersions)),
|
||||
put(updateProductVersions("firefox", channelVersions))
|
||||
);
|
||||
expect(data.saga.next().done).toBe(true);
|
||||
|
||||
console.error = jest.fn();
|
||||
data.sagaThrow.throw('error');
|
||||
data.sagaThrow.throw("error");
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
'Failed getting the latest channel versions for product: firefox',
|
||||
'error',
|
||||
"Failed getting the latest channel versions for product: firefox",
|
||||
"error"
|
||||
);
|
||||
expect(data.sagaThrow.next().done).toBe(true);
|
||||
});
|
||||
|
||||
it('handles updateUrl', () => {
|
||||
it("handles updateUrl", () => {
|
||||
const saga = updateUrl();
|
||||
|
||||
expect(saga.next().value).toEqual(select());
|
||||
expect(window.location.hash).not.toEqual('#pollbot/firefox/50.0');
|
||||
saga.next({version: ['firefox', '50.0']});
|
||||
expect(window.location.hash).toEqual('#pollbot/firefox/50.0');
|
||||
expect(window.location.hash).not.toEqual("#pollbot/firefox/50.0");
|
||||
saga.next({ version: ["firefox", "50.0"] });
|
||||
expect(window.location.hash).toEqual("#pollbot/firefox/50.0");
|
||||
});
|
||||
|
||||
it('notifies using checkResultAndUpdateAndNotify', () => {
|
||||
it("notifies using checkResultAndUpdateAndNotify", () => {
|
||||
// Mock the Notification API call.
|
||||
global.Notification = jest.fn();
|
||||
global.Notification.permission = 'granted';
|
||||
global.Notification.permission = "granted";
|
||||
|
||||
const checkResult = {
|
||||
status: 'exists',
|
||||
message: 'check succesful',
|
||||
link: 'some link',
|
||||
status: "exists",
|
||||
message: "check succesful",
|
||||
link: "some link"
|
||||
};
|
||||
const checkResultFailing = {
|
||||
status: 'incomplete',
|
||||
message: 'check incomplete',
|
||||
link: 'some link',
|
||||
status: "incomplete",
|
||||
message: "check incomplete",
|
||||
link: "some link"
|
||||
};
|
||||
|
||||
const data = {};
|
||||
data.saga = cloneableGenerator(checkResultAndUpdateAndNotify)(
|
||||
'some test',
|
||||
'some url',
|
||||
checkResultFailing,
|
||||
"some test",
|
||||
"some url",
|
||||
checkResultFailing
|
||||
);
|
||||
|
||||
expect(data.saga.next().value).toEqual(
|
||||
put(refreshCheckResult('some test')),
|
||||
put(refreshCheckResult("some test"))
|
||||
);
|
||||
|
||||
expect(data.saga.next().value).toEqual(
|
||||
call(checkResultAndUpdate, 'some test', 'some url'),
|
||||
call(checkResultAndUpdate, "some test", "some url")
|
||||
);
|
||||
expect(data.saga.next().value).toEqual(select());
|
||||
|
||||
|
@ -153,133 +153,133 @@ describe('sagas', () => {
|
|||
// No notification if the result hasn't changed.
|
||||
expect(
|
||||
data.sagaResultUnchanged.next({
|
||||
checkResults: {'some test': checkResultFailing},
|
||||
}).done,
|
||||
checkResults: { "some test": checkResultFailing }
|
||||
}).done
|
||||
).toBe(true);
|
||||
expect(global.Notification).toHaveBeenCalledTimes(0);
|
||||
|
||||
// Notify if the result has changed.
|
||||
expect(
|
||||
data.saga.next({
|
||||
checkResults: {'some test': checkResult},
|
||||
}).done,
|
||||
checkResults: { "some test": checkResult }
|
||||
}).done
|
||||
).toBe(true);
|
||||
expect(global.Notification).toHaveBeenCalledTimes(1);
|
||||
expect(global.Notification).toHaveBeenCalledWith(
|
||||
'some test: status changed (exists).',
|
||||
"some test: status changed (exists)."
|
||||
);
|
||||
});
|
||||
|
||||
it('handles refreshStatus', () => {
|
||||
it("handles refreshStatus", () => {
|
||||
const data = {};
|
||||
data.saga = cloneableGenerator(refreshStatus)();
|
||||
|
||||
const releaseInfo = {
|
||||
channel: 'release',
|
||||
product: 'firefox',
|
||||
version: '50.0',
|
||||
channel: "release",
|
||||
product: "firefox",
|
||||
version: "50.0",
|
||||
checks: [
|
||||
{
|
||||
title: 'some test',
|
||||
url: 'some url',
|
||||
title: "some test",
|
||||
url: "some url"
|
||||
},
|
||||
{
|
||||
title: 'some other test',
|
||||
url: 'some other url',
|
||||
},
|
||||
],
|
||||
title: "some other test",
|
||||
url: "some other url"
|
||||
}
|
||||
]
|
||||
};
|
||||
const checkResult = {
|
||||
status: 'exists',
|
||||
message: 'check succesful',
|
||||
link: 'some link',
|
||||
status: "exists",
|
||||
message: "check succesful",
|
||||
link: "some link"
|
||||
};
|
||||
const checkResultFailing = {
|
||||
status: 'incomplete',
|
||||
message: 'check incomplete',
|
||||
link: 'some link',
|
||||
status: "incomplete",
|
||||
message: "check incomplete",
|
||||
link: "some link"
|
||||
};
|
||||
|
||||
expect(data.saga.next().value).toEqual(select());
|
||||
|
||||
expect(
|
||||
data.saga.next({
|
||||
version: '50.0',
|
||||
version: "50.0",
|
||||
releaseInfo: releaseInfo,
|
||||
checkResults: {
|
||||
'some test': checkResult,
|
||||
'some other test': checkResultFailing,
|
||||
},
|
||||
}).value,
|
||||
"some test": checkResult,
|
||||
"some other test": checkResultFailing
|
||||
}
|
||||
}).value
|
||||
).toEqual(
|
||||
all([
|
||||
call(
|
||||
checkResultAndUpdateAndNotify,
|
||||
'some other test',
|
||||
'some other url',
|
||||
checkResultFailing,
|
||||
),
|
||||
]),
|
||||
"some other test",
|
||||
"some other url",
|
||||
checkResultFailing
|
||||
)
|
||||
])
|
||||
);
|
||||
expect(data.saga.next().done).toBe(true);
|
||||
});
|
||||
|
||||
it('checks result and updates state using checkResultAndUpdate', () => {
|
||||
it("checks result and updates state using checkResultAndUpdate", () => {
|
||||
const data = {};
|
||||
data.saga = cloneableGenerator(checkResultAndUpdate)(
|
||||
'some test',
|
||||
'some url',
|
||||
"some test",
|
||||
"some url"
|
||||
);
|
||||
|
||||
const checkResult = {
|
||||
status: 'exists',
|
||||
message: 'check succesful',
|
||||
link: 'some link',
|
||||
status: "exists",
|
||||
message: "check succesful",
|
||||
link: "some link"
|
||||
};
|
||||
|
||||
expect(data.saga.next().value).toEqual(call(checkStatus, 'some url'));
|
||||
expect(data.saga.next().value).toEqual(call(checkStatus, "some url"));
|
||||
|
||||
// Clone to test success and failure of checkStatus.
|
||||
data.sagaThrow = data.saga.clone();
|
||||
|
||||
// checkStatus throws an error.
|
||||
console.error = jest.fn();
|
||||
expect(data.sagaThrow.throw('error').value).toEqual(
|
||||
put(addServerError('some test', 'error')),
|
||||
expect(data.sagaThrow.throw("error").value).toEqual(
|
||||
put(addServerError("some test", "error"))
|
||||
);
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
'Failed getting some test check result',
|
||||
'error',
|
||||
"Failed getting some test check result",
|
||||
"error"
|
||||
);
|
||||
expect(data.sagaThrow.next().done).toBe(true);
|
||||
|
||||
// checkStatus completes correctly.
|
||||
expect(data.saga.next(checkResult).value).toEqual(
|
||||
put(addCheckResult('some test', checkResult)),
|
||||
put(addCheckResult("some test", checkResult))
|
||||
);
|
||||
});
|
||||
|
||||
it('handles requestStatus', () => {
|
||||
it("handles requestStatus", () => {
|
||||
const data = {};
|
||||
data.saga = cloneableGenerator(requestStatus)({
|
||||
product: 'firefox',
|
||||
version: '50.0',
|
||||
product: "firefox",
|
||||
version: "50.0"
|
||||
});
|
||||
|
||||
const releaseInfo = {
|
||||
channel: 'release',
|
||||
product: 'firefox',
|
||||
version: '50.0',
|
||||
channel: "release",
|
||||
product: "firefox",
|
||||
version: "50.0",
|
||||
checks: [
|
||||
{
|
||||
title: 'some test',
|
||||
url: 'some url',
|
||||
title: "some test",
|
||||
url: "some url"
|
||||
},
|
||||
{
|
||||
title: 'some other test',
|
||||
url: 'some other url',
|
||||
},
|
||||
],
|
||||
title: "some other test",
|
||||
url: "some other url"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
expect(data.saga.next().value).toEqual(select());
|
||||
|
@ -287,14 +287,14 @@ describe('sagas', () => {
|
|||
data.saga.next({
|
||||
productVersions: {
|
||||
firefox: {
|
||||
release: '50.0',
|
||||
},
|
||||
},
|
||||
}).value,
|
||||
).toEqual(put(setVersion('firefox', '50.0')));
|
||||
release: "50.0"
|
||||
}
|
||||
}
|
||||
}).value
|
||||
).toEqual(put(setVersion("firefox", "50.0")));
|
||||
expect(data.saga.next().value).toEqual(call(updateUrl));
|
||||
expect(data.saga.next().value).toEqual(
|
||||
call(getReleaseInfo, 'firefox', '50.0'),
|
||||
call(getReleaseInfo, "firefox", "50.0")
|
||||
);
|
||||
|
||||
// Clone to test success and failure of getReleaseInfo.
|
||||
|
@ -302,48 +302,48 @@ describe('sagas', () => {
|
|||
|
||||
// getReleaseInfo throws an error.
|
||||
console.error = jest.fn();
|
||||
data.sagaThrow.throw('error');
|
||||
data.sagaThrow.throw("error");
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
'Failed getting the release info for firefox 50.0',
|
||||
'error',
|
||||
"Failed getting the release info for firefox 50.0",
|
||||
"error"
|
||||
);
|
||||
expect(data.sagaThrow.next().done).toBe(true);
|
||||
|
||||
// getReleaseInfo completes correctly.
|
||||
expect(data.saga.next(releaseInfo).value).toEqual(
|
||||
put(updateReleaseInfo(releaseInfo)),
|
||||
put(updateReleaseInfo(releaseInfo))
|
||||
);
|
||||
expect(data.saga.next().value).toEqual(
|
||||
all([
|
||||
call(checkResultAndUpdate, 'some test', 'some url'),
|
||||
call(checkResultAndUpdate, 'some other test', 'some other url'),
|
||||
]),
|
||||
call(checkResultAndUpdate, "some test", "some url"),
|
||||
call(checkResultAndUpdate, "some other test", "some other url")
|
||||
])
|
||||
);
|
||||
expect(data.saga.next().done).toBe(true);
|
||||
});
|
||||
|
||||
it('handles requestStatus with a canonical url (using the channel)', () => {
|
||||
it("handles requestStatus with a canonical url (using the channel)", () => {
|
||||
const data = {};
|
||||
// Request status for "release", it should in turn set version for "50.0".
|
||||
data.saga = cloneableGenerator(requestStatus)({
|
||||
product: 'firefox',
|
||||
version: 'release',
|
||||
product: "firefox",
|
||||
version: "release"
|
||||
});
|
||||
|
||||
const releaseInfo = {
|
||||
channel: 'release',
|
||||
product: 'firefox',
|
||||
version: '50.0',
|
||||
channel: "release",
|
||||
product: "firefox",
|
||||
version: "50.0",
|
||||
checks: [
|
||||
{
|
||||
title: 'some test',
|
||||
url: 'some url',
|
||||
title: "some test",
|
||||
url: "some url"
|
||||
},
|
||||
{
|
||||
title: 'some other test',
|
||||
url: 'some other url',
|
||||
},
|
||||
],
|
||||
title: "some other test",
|
||||
url: "some other url"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
expect(data.saga.next().value).toEqual(select());
|
||||
|
@ -351,14 +351,14 @@ describe('sagas', () => {
|
|||
data.saga.next({
|
||||
productVersions: {
|
||||
firefox: {
|
||||
release: '50.0',
|
||||
},
|
||||
},
|
||||
}).value,
|
||||
).toEqual(put(setVersion('firefox', '50.0')));
|
||||
release: "50.0"
|
||||
}
|
||||
}
|
||||
}).value
|
||||
).toEqual(put(setVersion("firefox", "50.0")));
|
||||
expect(data.saga.next().value).toEqual(call(updateUrl));
|
||||
expect(data.saga.next().value).toEqual(
|
||||
call(getReleaseInfo, 'firefox', '50.0'),
|
||||
call(getReleaseInfo, "firefox", "50.0")
|
||||
);
|
||||
|
||||
// Clone to test success and failure of getReleaseInfo.
|
||||
|
@ -366,67 +366,67 @@ describe('sagas', () => {
|
|||
|
||||
// getReleaseInfo throws an error.
|
||||
console.error = jest.fn();
|
||||
data.sagaThrow.throw('error');
|
||||
data.sagaThrow.throw("error");
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
'Failed getting the release info for firefox 50.0',
|
||||
'error',
|
||||
"Failed getting the release info for firefox 50.0",
|
||||
"error"
|
||||
);
|
||||
expect(data.sagaThrow.next().done).toBe(true);
|
||||
|
||||
// getReleaseInfo completes correctly.
|
||||
expect(data.saga.next(releaseInfo).value).toEqual(
|
||||
put(updateReleaseInfo(releaseInfo)),
|
||||
put(updateReleaseInfo(releaseInfo))
|
||||
);
|
||||
expect(data.saga.next().value).toEqual(
|
||||
all([
|
||||
call(checkResultAndUpdate, 'some test', 'some url'),
|
||||
call(checkResultAndUpdate, 'some other test', 'some other url'),
|
||||
]),
|
||||
call(checkResultAndUpdate, "some test", "some url"),
|
||||
call(checkResultAndUpdate, "some other test", "some other url")
|
||||
])
|
||||
);
|
||||
expect(data.saga.next().done).toBe(true);
|
||||
});
|
||||
|
||||
it('handles requestStatus with a canonical url (using the channel) with a cold cache', () => {
|
||||
it("handles requestStatus with a canonical url (using the channel) with a cold cache", () => {
|
||||
const data = {};
|
||||
// Request status for "release", it should in turn set version for "50.0".
|
||||
data.saga = cloneableGenerator(requestStatus)({
|
||||
product: 'firefox',
|
||||
version: 'release',
|
||||
product: "firefox",
|
||||
version: "release"
|
||||
});
|
||||
|
||||
const releaseInfo = {
|
||||
channel: 'release',
|
||||
product: 'firefox',
|
||||
version: '50.0',
|
||||
channel: "release",
|
||||
product: "firefox",
|
||||
version: "50.0",
|
||||
checks: [
|
||||
{
|
||||
title: 'some test',
|
||||
url: 'some url',
|
||||
title: "some test",
|
||||
url: "some url"
|
||||
},
|
||||
{
|
||||
title: 'some other test',
|
||||
url: 'some other url',
|
||||
},
|
||||
],
|
||||
title: "some other test",
|
||||
url: "some other url"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
expect(data.saga.next().value).toEqual(select());
|
||||
expect(data.saga.next({productVersions: {}}).value).toEqual(
|
||||
call(getOngoingVersions, 'firefox'),
|
||||
expect(data.saga.next({ productVersions: {} }).value).toEqual(
|
||||
call(getOngoingVersions, "firefox")
|
||||
);
|
||||
expect(data.saga.next({release: '50.0'}).value).toEqual(
|
||||
put(updateProductVersions('firefox', {release: '50.0'})),
|
||||
expect(data.saga.next({ release: "50.0" }).value).toEqual(
|
||||
put(updateProductVersions("firefox", { release: "50.0" }))
|
||||
);
|
||||
|
||||
expect(data.saga.next().value).toEqual(select());
|
||||
expect(
|
||||
data.saga.next({
|
||||
productVersions: {firefox: {release: '50.0'}},
|
||||
}).value,
|
||||
).toEqual(put(setVersion('firefox', '50.0')));
|
||||
productVersions: { firefox: { release: "50.0" } }
|
||||
}).value
|
||||
).toEqual(put(setVersion("firefox", "50.0")));
|
||||
expect(data.saga.next().value).toEqual(call(updateUrl));
|
||||
expect(data.saga.next().value).toEqual(
|
||||
call(getReleaseInfo, 'firefox', '50.0'),
|
||||
call(getReleaseInfo, "firefox", "50.0")
|
||||
);
|
||||
|
||||
// Clone to test success and failure of getReleaseInfo.
|
||||
|
@ -434,29 +434,29 @@ describe('sagas', () => {
|
|||
|
||||
// getReleaseInfo throws an error.
|
||||
console.error = jest.fn();
|
||||
data.sagaThrow.throw('error');
|
||||
data.sagaThrow.throw("error");
|
||||
expect(console.error).toHaveBeenCalledWith(
|
||||
'Failed getting the release info for firefox 50.0',
|
||||
'error',
|
||||
"Failed getting the release info for firefox 50.0",
|
||||
"error"
|
||||
);
|
||||
expect(data.sagaThrow.next().done).toBe(true);
|
||||
|
||||
// getReleaseInfo completes correctly.
|
||||
expect(data.saga.next(releaseInfo).value).toEqual(
|
||||
put(updateReleaseInfo(releaseInfo)),
|
||||
put(updateReleaseInfo(releaseInfo))
|
||||
);
|
||||
expect(data.saga.next().value).toEqual(
|
||||
all([
|
||||
call(checkResultAndUpdate, 'some test', 'some url'),
|
||||
call(checkResultAndUpdate, 'some other test', 'some other url'),
|
||||
]),
|
||||
call(checkResultAndUpdate, "some test", "some url"),
|
||||
call(checkResultAndUpdate, "some other test", "some other url")
|
||||
])
|
||||
);
|
||||
expect(data.saga.next().done).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('rootSaga', () => {
|
||||
it('uses takeEvery on each saga available', () => {
|
||||
describe("rootSaga", () => {
|
||||
it("uses takeEvery on each saga available", () => {
|
||||
const saga = rootSaga();
|
||||
expect(saga.next().value).toEqual(
|
||||
all([
|
||||
|
@ -464,8 +464,8 @@ describe('rootSaga', () => {
|
|||
takeEvery(REQUEST_POLLBOT_VERSION, fetchPollbotVersion),
|
||||
takeEvery(UPDATE_URL, updateUrl),
|
||||
takeEvery(REFRESH_STATUS, refreshStatus),
|
||||
takeEvery(REQUEST_STATUS, requestStatus),
|
||||
]),
|
||||
takeEvery(REQUEST_STATUS, requestStatus)
|
||||
])
|
||||
);
|
||||
expect(saga.next().done).toBe(true);
|
||||
});
|
||||
|
|
90
src/types.js
90
src/types.js
|
@ -3,28 +3,28 @@ import type {
|
|||
Store as ReduxStore,
|
||||
ThunkAction as ReduxThunkAction,
|
||||
Dispatch as ReduxDispatch,
|
||||
GetState as ReduxGetState,
|
||||
} from 'redux';
|
||||
GetState as ReduxGetState
|
||||
} from "redux";
|
||||
|
||||
export const products = ['firefox', 'devedition'];
|
||||
export const products = ["firefox", "devedition"];
|
||||
|
||||
/*
|
||||
* state types
|
||||
*/
|
||||
export type Product = 'firefox' | 'devedition';
|
||||
export type Status = 'missing' | 'exists' | 'incomplete' | 'error';
|
||||
export type Product = "firefox" | "devedition";
|
||||
export type Status = "missing" | "exists" | "incomplete" | "error";
|
||||
|
||||
export type ChannelVersion = [string, string];
|
||||
export type ChannelVersions = ChannelVersion[];
|
||||
export type VersionsDict = {[channel: string]: string};
|
||||
export type VersionsDict = { [channel: string]: string };
|
||||
export type ProductVersions = {
|
||||
[product: Product]: VersionsDict,
|
||||
[product: Product]: VersionsDict
|
||||
};
|
||||
|
||||
export type CheckInfo = {
|
||||
+url: string,
|
||||
+title: string,
|
||||
+actionable: boolean,
|
||||
+actionable: boolean
|
||||
};
|
||||
|
||||
export type ReleaseInfo = {
|
||||
|
@ -33,24 +33,24 @@ export type ReleaseInfo = {
|
|||
+version: string,
|
||||
+checks: CheckInfo[],
|
||||
+message: string,
|
||||
+status: number,
|
||||
+status: number
|
||||
};
|
||||
|
||||
export type CheckResult = {
|
||||
+status: Status,
|
||||
+message: string,
|
||||
+link: string,
|
||||
+link: string
|
||||
};
|
||||
|
||||
export type CheckResults = {
|
||||
[check: string]: CheckResult,
|
||||
[check: string]: CheckResult
|
||||
};
|
||||
|
||||
export type APIVersionData = {
|
||||
name: string,
|
||||
version: string,
|
||||
source: string,
|
||||
commit: string,
|
||||
commit: string
|
||||
};
|
||||
|
||||
/* Error: [title, errorMessage] */
|
||||
|
@ -63,82 +63,82 @@ export type State = {
|
|||
+checkResults: CheckResults,
|
||||
+pollbotVersion: ?APIVersionData,
|
||||
+shouldRefresh: boolean,
|
||||
+errors: Error[],
|
||||
+errors: Error[]
|
||||
};
|
||||
|
||||
/*
|
||||
* action types
|
||||
*/
|
||||
export const ADD_CHECK_RESULT = 'ADD_CHECK_RESULT';
|
||||
export const REFRESH_CHECK_RESULT = 'REFRESH_CHECK_RESULT';
|
||||
export const ADD_SERVER_ERROR = 'ADD_SERVER_ERROR';
|
||||
export const SET_VERSION = 'SET_VERSION';
|
||||
export const UPDATE_PRODUCT_VERSIONS = 'UPDATE_PRODUCT_VERSIONS';
|
||||
export const UPDATE_RELEASE_INFO = 'UPDATE_RELEASE_INFO';
|
||||
export const UPDATE_POLLBOT_VERSION = 'UPDATE_POLLBOT_VERSION';
|
||||
export const ADD_CHECK_RESULT = "ADD_CHECK_RESULT";
|
||||
export const REFRESH_CHECK_RESULT = "REFRESH_CHECK_RESULT";
|
||||
export const ADD_SERVER_ERROR = "ADD_SERVER_ERROR";
|
||||
export const SET_VERSION = "SET_VERSION";
|
||||
export const UPDATE_PRODUCT_VERSIONS = "UPDATE_PRODUCT_VERSIONS";
|
||||
export const UPDATE_RELEASE_INFO = "UPDATE_RELEASE_INFO";
|
||||
export const UPDATE_POLLBOT_VERSION = "UPDATE_POLLBOT_VERSION";
|
||||
|
||||
export type AddCheckResult = {|
|
||||
type: 'ADD_CHECK_RESULT',
|
||||
type: "ADD_CHECK_RESULT",
|
||||
title: string,
|
||||
result: CheckResult,
|
||||
result: CheckResult
|
||||
|};
|
||||
export type RefreshCheckResult = {|
|
||||
type: 'REFRESH_CHECK_RESULT',
|
||||
title: string,
|
||||
type: "REFRESH_CHECK_RESULT",
|
||||
title: string
|
||||
|};
|
||||
export type AddServerError = {|
|
||||
type: 'ADD_SERVER_ERROR',
|
||||
type: "ADD_SERVER_ERROR",
|
||||
title: string,
|
||||
err: string,
|
||||
err: string
|
||||
|};
|
||||
export type SetVersion = {|
|
||||
type: 'SET_VERSION',
|
||||
type: "SET_VERSION",
|
||||
product: Product,
|
||||
version: string,
|
||||
version: string
|
||||
|};
|
||||
export type UpdateProductVersions = {|
|
||||
type: 'UPDATE_PRODUCT_VERSIONS',
|
||||
type: "UPDATE_PRODUCT_VERSIONS",
|
||||
versions: VersionsDict,
|
||||
product: Product,
|
||||
product: Product
|
||||
|};
|
||||
export type UpdateReleaseInfo = {|
|
||||
type: 'UPDATE_RELEASE_INFO',
|
||||
releaseInfo: ReleaseInfo,
|
||||
type: "UPDATE_RELEASE_INFO",
|
||||
releaseInfo: ReleaseInfo
|
||||
|};
|
||||
export type UpdatePollbotVersion = {|
|
||||
type: 'UPDATE_POLLBOT_VERSION',
|
||||
version: APIVersionData,
|
||||
type: "UPDATE_POLLBOT_VERSION",
|
||||
version: APIVersionData
|
||||
|};
|
||||
|
||||
/*
|
||||
* saga types
|
||||
*/
|
||||
export const REQUEST_ONGOING_VERSIONS = 'REQUEST_ONGOING_VERSIONS';
|
||||
export const REQUEST_POLLBOT_VERSION = 'REQUEST_POLLBOT_VERSION';
|
||||
export const UPDATE_URL = 'UPDATE_URL';
|
||||
export const REFRESH_STATUS = 'REFRESH_STATUS';
|
||||
export const REQUEST_STATUS = 'REQUEST_STATUS';
|
||||
export const REQUEST_ONGOING_VERSIONS = "REQUEST_ONGOING_VERSIONS";
|
||||
export const REQUEST_POLLBOT_VERSION = "REQUEST_POLLBOT_VERSION";
|
||||
export const UPDATE_URL = "UPDATE_URL";
|
||||
export const REFRESH_STATUS = "REFRESH_STATUS";
|
||||
export const REQUEST_STATUS = "REQUEST_STATUS";
|
||||
|
||||
export type RequestOngoingVersions = {|
|
||||
type: 'REQUEST_ONGOING_VERSIONS',
|
||||
type: "REQUEST_ONGOING_VERSIONS"
|
||||
|};
|
||||
|
||||
export type RequestPollbotVersion = {|
|
||||
type: 'REQUEST_POLLBOT_VERSION',
|
||||
type: "REQUEST_POLLBOT_VERSION"
|
||||
|};
|
||||
|
||||
export type UpdateUrl = {|
|
||||
type: 'UPDATE_URL',
|
||||
type: "UPDATE_URL"
|
||||
|};
|
||||
|
||||
export type RefreshStatus = {|
|
||||
type: 'REFRESH_STATUS',
|
||||
type: "REFRESH_STATUS"
|
||||
|};
|
||||
|
||||
export type RequestStatus = {|
|
||||
type: 'REQUEST_STATUS',
|
||||
type: "REQUEST_STATUS",
|
||||
product: Product,
|
||||
version: string,
|
||||
version: string
|
||||
|};
|
||||
|
||||
export type Action =
|
||||
|
|
Загрузка…
Ссылка в новой задаче