Compare commits

...
28 Commits
Author SHA1 Message Date
kyle 253573200a release: 3.9.1 (#4106)
* fix(core-components): make `onToggle` a non-required prop in ModelCollapse

* release: 3.9.1
2018-01-13 01:30:37 -06:00
diegospd 024b7db81e fix(docs): correct tranditional typo (#4104) 2018-01-12 16:39:13 -06:00
David Muto 5b1dbec9b0 feature(docker-image): allow custom nginx port within container (#4086)
* Use PORT to override nginx listen port when defined
* Add dockerignore to make build context smaller
2018-01-12 13:52:09 -06:00
Lukasr29 64f99356a5 improve(tio): extract file name from Content-Disposition (#4035)
* Added extraction of quoted file name from content disposition header

* Added extraction of quoted file name from content disposition header - PR Fixes

* Added extraction of quoted file name from content disposition header - PR Fixes

* Added extraction of quoted file name from content disposition header - PR Fixes
2018-01-11 19:39:42 -06:00
linelson b3e80cc500 fix(tic-validation): uuid format parameter validation should be case insensitive (#4102)
* fix uuid validation casing (#4099)
* add test
2018-01-11 18:42:37 -06:00
kyle 53ea2003c1 improve(npm-module): include standalone preset in swagger-ui (#4101) 2018-01-11 18:39:13 -06:00
Udit Desai a037c7205b improve(docker-image): symlink swagger.json from app directory to nginx (#4024) 2018-01-11 17:06:56 -06:00
kyle 63d5f164c6 fix(core-components): make onToggle a non-required prop in ModelCollapse (#4100) 2018-01-11 16:56:36 -06:00
Helen Kosova 2e816e0440 fix(docs): broken link in the issue template (#4094) 2018-01-10 18:32:33 -06:00
kyle 0818882a90 v3.9.0 (#4078) 2018-01-06 02:27:11 -06:00
kyle 0751022b77 bug(polyfiller): check for Promise on global/window object 2018-01-06 00:19:29 -06:00
kyle fc070408f6 docs(contributing): add merging pull requests section (#4076) 2018-01-05 22:34:04 -06:00
David DE CARVALHO a47da98b54 feat(render/parameters): display enums, defaults, and examples when not in TIO mode 2018-01-05 22:09:32 -06:00
narutowyh 12a9fbc0ca fix: ignore prototype's keys in a handful of for...in loops 2018-01-05 21:57:17 -06:00
Juan J. Jimenez-Anca bd41b736a8 feat: display last error when definition/config load fails
Contains a breaking internal API change to `errActions.newThrownErr`, which will require a MINOR version bump. Swagger-Editor does not depend on the old usage style.
2018-01-05 21:45:21 -06:00
kyle a8f204181e Merge pull request #4075 from jenglish404/patch-2
Make parameter description styles consistent
2018-01-05 20:51:23 -06:00
kyle 67d472acc7 Merge branch 'master' into patch-2 2018-01-05 20:07:03 -06:00
kyle aebcfe8e5d Merge pull request #4073 from champjss/master
Change nginx configuration in Docker container based on BASE_URL, instead of moving actual files
2018-01-05 19:23:24 -06:00
jenglish404 71c0742735 Make parameter description styles consistent
Remove .swagger-ui .parameters-col_description p formatting from _table.scss. With this in place, the parameter descriptions are bold and a larger font for request parameters. This is inconsistent with how response values are displayed.
2018-01-05 15:17:22 -08:00
Jatesadakarn Saengrat 8e4f94b33f Change nginx configuration based on BASE_URL, instead of moving actual files 2018-01-05 18:56:30 +07:00
kyle a9ea10da2c Merge pull request #4037 from scop/zopflipng
Run *.png through zopflipng -m
2018-01-03 18:58:49 -06:00
kyle 8f3535b5ff Merge branch 'master' into zopflipng 2018-01-03 18:55:00 -06:00
kyle 0ca0b8120f Merge pull request #4067 from shockey/master
Add try/catch protection for statePlugin interfaces
2018-01-03 16:54:27 -06:00
kyle 603c436427 Merge branch 'master' into master 2018-01-03 16:37:15 -06:00
Kyle Shockey c601f9b0ca Add try/catch protection for statePlugin interfaces 2018-01-03 13:59:48 -06:00
kyle c742df9573 Merge pull request #4066 from swagger-api/the-year-is-now-2018
Happy new year 🎉
2018-01-02 15:36:12 -06:00
kyle ecfda531de Happy new year 🎉 2018-01-02 15:33:04 -06:00
Ville Skyttä 8c4b511227 Run *.png through zopflipng -m 2017-12-16 22:42:14 +02:00
39 changed files with 494 additions and 190 deletions
+7
View File
@@ -0,0 +1,7 @@
/.git
/.github
/dev-helpers
/docs
/src
/swagger-ui-dist-package
/test
+1 -1
View File
@@ -18,7 +18,7 @@ or anything that violates the specifications.
<!--- Provide a general summary of the issue in the title above -->
<!---
If you aren't sure what Swagger-UI version, see this guide: https://github.com/swagger-api/swagger-ui/blob/master/docs/version-detection.md
If you aren't sure what Swagger-UI version, see this guide: https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/version-detection.md
--->
+2
View File
@@ -4,6 +4,8 @@
!package.json
!dist/swagger-ui.js
!dist/swagger-ui.js.map
!dist/swagger-ui-standalone-preset.js
!dist/swagger-ui-standalone-preset.js.map
!dist/swagger-ui.css
!dist/swagger-ui.css.map
!dist/oauth2-redirect.html
+4
View File
@@ -52,3 +52,7 @@ _Adapted from [How to Write a Git Commit Message](https://chris.beams.io/posts/g
- **Don't** include any changes to files in the `dist/` directory - we update those files only during releases.
- **Don't** mention maintainers in your original PR body - we probably would've seen it anyway, so it just increases the noise in our inboxes. Do feel free to ping maintainers if a week has passed and you've heard nothing from us.
- **Don't** open PRs for custom functionality that only serves a small subset of our users - custom functionality should be implemented outside of our codebase, via a plugin.
#### Merging pull requests
- **Do** use GitHub's `Squash and merge` strategy.
- **Do** follow the [Conventional Commits](https://conventionalcommits.org) standard format for your squash commit.
+1 -1
View File
@@ -12,7 +12,7 @@ ENV OAUTH_REALM "**None**"
ENV OAUTH_APP_NAME "**None**"
ENV OAUTH_ADDITIONAL_PARAMS "**None**"
ENV SWAGGER_JSON "/app/swagger.json"
ENV PORT 80
ENV PORT 8080
ENV BASE_URL ""
RUN apk add --update nginx
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright 2017 SmartBear Software
Copyright 2018 SmartBear Software
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
+1 -1
View File
@@ -22,7 +22,7 @@ The OpenAPI Specification has undergone 5 revisions since initial creation in 20
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes
------------------ | ------------ | -------------------------- | -----
3.8.0 | 2017-12-15 | 2.0, 3.0 | [tag v3.8.1](https://github.com/swagger-api/swagger-ui/tree/v3.8.1)
3.9.1 | 2018-01-12 | 2.0, 3.0 | [tag v3.9.1](https://github.com/swagger-api/swagger-ui/tree/v3.9.1)
3.0.21 | 2017-07-26 | 2.0 | [tag v3.0.21](https://github.com/swagger-api/swagger-ui/tree/v3.0.21)
2.2.10 | 2017-01-04 | 1.1, 1.2, 2.0 | [tag v2.2.10](https://github.com/swagger-api/swagger-ui/tree/v2.2.10)
2.1.5 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5)
+14 -14
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+6 -8
View File
@@ -2,6 +2,7 @@
set -e
BASE_URL=${BASE_URL:-/}
NGINX_ROOT=/usr/share/nginx/html
INDEX_FILE=$NGINX_ROOT/index.html
@@ -22,13 +23,7 @@ replace_or_delete_in_index () {
}
if [ "${BASE_URL}" ]; then
NGINX_WITH_BASE_URL="${NGINX_ROOT}${BASE_URL}"
mkdir -p ${NGINX_WITH_BASE_URL}
mv ${NGINX_ROOT}/*.* ${NGINX_WITH_BASE_URL}/
INDEX_FILE=$NGINX_WITH_BASE_URL/index.html
NGINX_ROOT=$NGINX_WITH_BASE_URL
sed -i "s|location .* {|location $BASE_URL {|g" /etc/nginx/nginx.conf
fi
replace_in_index myApiKeyXXXX123456789 $API_KEY
@@ -41,7 +36,7 @@ if [ "$OAUTH_ADDITIONAL_PARAMS" != "**None**" ]; then
fi
if [[ -f $SWAGGER_JSON ]]; then
cp $SWAGGER_JSON $NGINX_ROOT
cp -s $SWAGGER_JSON $NGINX_ROOT
REL_PATH="./$(basename $SWAGGER_JSON)"
sed -i "s|http://petstore.swagger.io/v2/swagger.json|$REL_PATH|g" $INDEX_FILE
sed -i "s|http://example.com/api|$REL_PATH|g" $INDEX_FILE
@@ -58,4 +53,7 @@ if [[ -n "$VALIDATOR_URL" ]]; then
unset TMP_VU
fi
# replace the PORT that nginx listens on if supplied
if [[ -n "${PORT}" ]]; then sed -i "s|8080|${PORT}|g" /etc/nginx/nginx.conf; fi
exec nginx -g 'daemon off;'
Binary file not shown.

Before

Width:  |  Height:  |  Size: 390 KiB

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 297 KiB

After

Width:  |  Height:  |  Size: 126 KiB

+1 -1
View File
@@ -37,7 +37,7 @@ app.listen(3000)
```
The module also exports `SwaggerUIBundle` and `SwaggerUIStandalonePreset`, so
if you're in a JavaScript project that can't handle a tranditional npm module,
if you're in a JavaScript project that can't handle a traditional npm module,
you could do something like this:
```js
+3 -2
View File
@@ -15,10 +15,11 @@ http {
server {
listen 8080;
server_name localhost;
index index.html index.htm;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
alias /usr/share/nginx/html/;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "swagger-ui",
"version": "3.8.1",
"version": "3.9.1",
"main": "dist/swagger-ui.js",
"repository": "git@github.com:swagger-api/swagger-ui.git",
"contributors": [
@@ -82,7 +82,7 @@
"scroll-to-element": "^2.0.0",
"serialize-error": "2.0.0",
"shallowequal": "0.2.2",
"swagger-client": "^3.4.4",
"swagger-client": "^3.4.5",
"url-parse": "^1.1.8",
"whatwg-fetch": "0.11.1",
"worker-loader": "^0.7.1",
+3
View File
@@ -57,6 +57,9 @@ export class Col extends React.Component {
let classesAr = []
for (let device in DEVICES) {
if (!DEVICES.hasOwnProperty(device)) {
continue
}
let deviceClass = DEVICES[device]
if(device in this.props) {
let val = this.props[device]
+3 -2
View File
@@ -8,13 +8,14 @@ export default class ModelCollapse extends Component {
children: PropTypes.any,
title: PropTypes.element,
modelName: PropTypes.string,
onToggle: PropTypes.func.isRequired
onToggle: PropTypes.func
}
static defaultProps = {
collapsedContent: "{...}",
expanded: false,
title: null
title: null,
onToggle: () => {}
}
constructor(props, context) {
+1 -1
View File
@@ -12,7 +12,7 @@ export default class ObjectModel extends Component {
getComponent: PropTypes.func.isRequired,
getConfigs: PropTypes.func.isRequired,
expanded: PropTypes.bool,
onToggle: PropTypes.func.isRequired,
onToggle: PropTypes.func,
specSelectors: PropTypes.object.isRequired,
name: PropTypes.string,
isRef: PropTypes.bool,
+47
View File
@@ -108,6 +108,34 @@ export default class ParameterRow extends Component {
let value = parameter ? parameter.get("value") : ""
let extensions = getExtensions(param)
let paramItems // undefined
let paramItemsEnum // undefined
let isDisplayParamItemsEnum = false
if ( param !== undefined ) {
paramItems = param.get("items")
}
if ( paramItems !== undefined ) {
paramItemsEnum = param.get("items").get("enum")
}
if ( paramItemsEnum !== undefined ) {
if (paramItemsEnum.size > 0) {
isDisplayParamItemsEnum = true
}
}
// Default and Example Value for readonly doc
let paramDefaultValue // undefined
let paramExample // undefined
if ( param !== undefined ) {
paramDefaultValue = param.get("default")
paramExample = param.get("example")
}
if (isDisplayParamItemsEnum) { // if we have an array, default value is in "items"
paramDefaultValue = paramItems.get("default")
}
return (
<tr>
<td className="col parameters-col_name">
@@ -125,6 +153,25 @@ export default class ParameterRow extends Component {
<td className="col parameters-col_description">
<Markdown source={ param.get("description") }/>
{ (bodyParam || !isExecute) && isDisplayParamItemsEnum ?
<Markdown source={
"<i>Available values</i> : " + paramItemsEnum.map(function(item) {
return item
}).toArray()}/>
: null
}
{ (bodyParam || !isExecute) && paramDefaultValue !== undefined ?
<Markdown source={"<i>Default value</i> : " + paramDefaultValue}/>
: null
}
{ (bodyParam || !isExecute) && paramExample !== undefined ?
<Markdown source={"<i>Example</i> : " + paramExample}/>
: null
}
{(isFormData && !isFormDataSupported) && <div>Error: your browser does not support FormData</div>}
{ bodyParam || !isExecute ? null
+6 -4
View File
@@ -2,6 +2,7 @@ import React from "react"
import PropTypes from "prop-types"
import formatXml from "xml-but-prettier"
import lowerCase from "lodash/lowerCase"
import { extractFileNameFromContentDispositionHeader } from "core/utils"
export default class ResponseBody extends React.Component {
@@ -70,12 +71,13 @@ export default class ResponseBody extends React.Component {
let fileName = url.substr(url.lastIndexOf("/") + 1)
let download = [type, fileName, href].join(":")
// Use filename from response header
// Use filename from response header,
// First check if filename is quoted (e.g. contains space), if no, fallback to not quoted check
let disposition = headers["content-disposition"] || headers["Content-Disposition"]
if (typeof disposition !== "undefined") {
let responseFilename = /filename=([^;]*);?/i.exec(disposition)
if (responseFilename !== null && responseFilename.length > 1) {
download = responseFilename[1]
let responseFilename = extractFileNameFromContentDispositionHeader(disposition)
if (responseFilename !== null) {
download = responseFilename
}
}
+1 -1
View File
@@ -26,7 +26,7 @@ export default function downloadUrlPlugin (toolbox) {
function next(res) {
if(res instanceof Error || res.status >= 400) {
specActions.updateLoadingStatus("failed")
return errActions.newThrownErr( new Error(res.statusText + " " + url) )
return errActions.newThrownErr( new Error((res.message || res.statusText) + " " + url) )
}
specActions.updateLoadingStatus("success")
specActions.updateSpec(res.text)
+2 -2
View File
@@ -7,10 +7,10 @@ export const NEW_SPEC_ERR_BATCH = "err_new_spec_err_batch"
export const NEW_AUTH_ERR = "err_new_auth_err"
export const CLEAR = "err_clear"
export function newThrownErr(err, action) {
export function newThrownErr(err) {
return {
type: NEW_THROWN_ERR,
payload: { action, error: serializeError(err) }
payload: serializeError(err)
}
}
+3
View File
@@ -181,6 +181,9 @@ export const sampleXmlFromSchema = (schema, config={}) => {
example = example || {}
for (let propName in props) {
if (!props.hasOwnProperty(propName)) {
continue
}
if ( props[propName].readOnly && !includeReadOnly ) {
continue
}
+28 -7
View File
@@ -18,7 +18,6 @@ function createStoreWithMiddleware(rootReducer, initialState, getSystem) {
// createLogger( {
// stateTransformer: state => state && state.toJS()
// } ),
// errorLog(getSystem), Need to properly handle errors that occur during a render. Ie: let them be...
systemThunkMiddleware( getSystem )
]
@@ -176,7 +175,7 @@ export default class Store {
if(!isFn(newAction)) {
throw new TypeError("wrapActions needs to return a function that returns a new function (ie the wrapped action)")
}
return newAction
return wrapWithTryCatch(newAction)
}, action || Function.prototype)
})
}
@@ -256,11 +255,11 @@ export default class Store {
return objMap(obj, (fn) => {
return (...args) => {
let res = fn.apply(null, [getNestedState(), ...args])
let res = wrapWithTryCatch(fn).apply(null, [getNestedState(), ...args])
// If a selector returns a function, give it the system - for advanced usage
if(typeof(res) === "function")
res = res(getSystem())
res = wrapWithTryCatch(res)(getSystem())
return res
}
@@ -331,7 +330,7 @@ function callAfterLoad(plugins, system, { hasLoaded } = {}) {
if(isObject(plugins) && !isArray(plugins)) {
if(typeof plugins.afterLoad === "function") {
calledSomething = true
plugins.afterLoad.call(this, system)
wrapWithTryCatch(plugins.afterLoad).call(this, system)
}
}
@@ -436,14 +435,36 @@ function makeReducer(reducerObj) {
if(!reducerObj)
return state
let redFn = reducerObj[action.type]
let redFn = (reducerObj[action.type])
if(redFn) {
return redFn(state, action)
const res = wrapWithTryCatch(redFn)(state, action)
// If the try/catch wrapper kicks in, we'll get null back...
// in that case, we want to avoid making any changes to state
return res === null ? state : res
}
return state
}
}
function wrapWithTryCatch(fn, {
logErrors = true
} = {}) {
if(typeof fn !== "function") {
return fn
}
return function(...args) {
try {
return fn.call(this, ...args)
} catch(e) {
if(logErrors) {
console.error(e)
}
return null
}
}
}
function configureStore(rootReducer, initialState, getSystem) {
const store = createStoreWithMiddleware(rootReducer, initialState, getSystem)
+15 -9
View File
@@ -126,15 +126,6 @@ export function systemThunkMiddleware(getSystem) {
}
}
export const errorLog = getSystem => () => next => action => {
try{
next( action )
}
catch( e ) {
getSystem().errActions.newThrownErr( e, action )
}
}
export function defaultStatusCode ( responses ) {
let codes = responses.keySeq()
return codes.contains(DEFAULT_REPONSE_KEY) ? DEFAULT_REPONSE_KEY : codes.filter( key => (key+"")[0] === "2").sort().first()
@@ -351,6 +342,17 @@ export function mapToList(map, keyNames="key", collectedKeys=Im.Map()) {
return list
}
export function extractFileNameFromContentDispositionHeader(value){
let responseFilename = /filename="([^;]*);?"/i.exec(value)
if (responseFilename === null) {
responseFilename = /filename=([^;]*);?/i.exec(value)
}
if (responseFilename !== null && responseFilename.length > 1) {
return responseFilename[1]
}
return null
}
// PascalCase, aka UpperCamelCase
export function pascalCase(str) {
return upperFirst(camelCase(str))
@@ -442,6 +444,7 @@ export const validateDateTime = (val) => {
}
export const validateGuid = (val) => {
val = val.toString().toLowerCase()
if (!/^[{(]?[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}[)}]?$/.test(val)) {
return "Value must be a Guid"
}
@@ -616,6 +619,9 @@ export const parseSearch = () => {
let params = search.substr(1).split("&")
for (let i in params) {
if (!params.hasOwnProperty(i)) {
continue
}
i = params[i].split("=")
map[decodeURIComponent(i[0])] = decodeURIComponent(i[1])
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 770 B

After

Width:  |  Height:  |  Size: 458 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 770 B

After

Width:  |  Height:  |  Size: 458 B

+3 -1
View File
@@ -1,6 +1,8 @@
// Promise global, Used ( at least ) by 'whatwg-fetch'. And required by IE 11
if(typeof Promise === "undefined") {
import win from "core/window"
if(typeof win.Promise === "undefined") {
require("core-js/fn/promise")
}
+9 -3
View File
@@ -16,7 +16,7 @@ export default class StandaloneLayout extends React.Component {
}
render() {
let { getComponent, specSelectors } = this.props
let { getComponent, specSelectors, errSelectors } = this.props
let Container = getComponent("Container")
let Row = getComponent("Row")
@@ -27,6 +27,8 @@ export default class StandaloneLayout extends React.Component {
const OnlineValidatorBadge = getComponent("onlineValidatorBadge", true)
const loadingStatus = specSelectors.loadingStatus()
const lastErr = errSelectors.lastError()
const lastErrMsg = lastErr ? lastErr.get("message") : ""
return (
@@ -43,12 +45,16 @@ export default class StandaloneLayout extends React.Component {
<div className="info">
<div className="loading-container">
<h4 className="title">Failed to load API definition.</h4>
</div>
<p>{lastErrMsg}</p>
</div>
</div>
}
{ loadingStatus === "failedConfig" &&
<div className="info" style={{ maxWidth: "880px", marginLeft: "auto", marginRight: "auto", textAlign: "center" }}>
<h4 className="title">Failed to load remote configuration.</h4>
<div className="loading-container">
<h4 className="title">Failed to load remote configuration.</h4>
<p>{lastErrMsg}</p>
</div>
</div>
}
{ !loadingStatus || loadingStatus === "success" && <BaseLayout /> }
+2
View File
@@ -657,6 +657,8 @@
min-height: 1px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
.loading
{
-9
View File
@@ -84,15 +84,6 @@ table
.parameters-col_description
{
p
{
font-size: 14px;
margin: 0;
@include text_body();
}
input[type=text]
{
width: 100%;
+295 -110
View File
@@ -571,116 +571,6 @@ describe("bound system", function(){
// Then
expect(renderedComponent.text()).toEqual("This came from mapStateToProps and this came from the system and this came from my own props")
})
it("should catch errors thrown inside of React Component Class render methods", function() {
// Given
// eslint-disable-next-line react/require-render-return
class BrokenComponent extends React.Component {
render() {
throw new Error("This component is broken")
}
}
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var Component = system.getSystem().getComponent("BrokenComponent")
const renderedComponent = render(<Component />)
// Then
expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
it("should catch errors thrown inside of pure component render methods", function() {
// Given
// eslint-disable-next-line react/require-render-return
class BrokenComponent extends PureComponent {
render() {
throw new Error("This component is broken")
}
}
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var Component = system.getSystem().getComponent("BrokenComponent")
const renderedComponent = render(<Component />)
// Then
expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
it("should catch errors thrown inside of stateless component functions", function() {
// Given
// eslint-disable-next-line react/require-render-return
let BrokenComponent = function BrokenComponent() { throw new Error("This component is broken") }
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var Component = system.getSystem().getComponent("BrokenComponent")
const renderedComponent = render(<Component />)
// Then
expect(renderedComponent.text().startsWith("😱 Could not render")).toEqual(true)
})
it("should catch errors thrown inside of container components", function() {
// Given
// eslint-disable-next-line react/require-render-return
class BrokenComponent extends React.Component {
render() {
throw new Error("This component is broken")
}
}
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var Component = system.getSystem().getComponent("BrokenComponent", true)
const renderedComponent = render(
<Provider store={system.getStore()}>
<Component />
</Provider>
)
// Then
expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
})
describe("afterLoad", function() {
@@ -793,4 +683,299 @@ describe("bound system", function(){
expect(res).toEqual("so selective")
})
})
describe("error catching", function() {
it("should encapsulate thrown errors in an afterLoad method", function() {
// Given
const ThrowyPlugin = {
afterLoad(system) {
throw new Error("afterLoad BREAKS STUFF!")
},
statePlugins: {
doge: {
selectors: {
wow: () => (system) => {
return "so selective"
}
}
}
}
}
const system = new System({
plugins: []
})
// When
expect(function() {
system.register([ThrowyPlugin])
// var resSystem = system.getSystem()
}).toNotThrow()
})
it("should encapsulate thrown errors in an action creator", function(){
// Given
const system = new System({
plugins: {
statePlugins: {
throw: {
actions: {
func() {
throw new Error("this action creator THROWS!")
}
}
}
}
}
})
expect(function() {
// TODO: fix existing action error catcher that creates THROWN ERR actions
system.getSystem().throwActions.func()
}).toNotThrow()
})
it("should encapsulate thrown errors in a reducer", function(){
// Given
const system = new System({
plugins: {
statePlugins: {
throw: {
actions: {
func: () => {
return {
type: "THROW_FUNC",
payload: "BOOM!"
}
}
},
reducers: {
"THROW_FUNC": (state, action) => {
throw new Error("this reducer EXPLODES!")
}
}
}
}
}
})
expect(function() {
system.getSystem().throwActions.func()
}).toNotThrow()
})
it("should encapsulate thrown errors in a selector", function(){
// Given
const system = new System({
plugins: {
statePlugins: {
throw: {
selectors: {
func: (state, arg1) => {
throw new Error("this selector THROWS!")
}
}
}
}
}
})
expect(system.getSystem().throwSelectors.func).toNotThrow()
})
it("should encapsulate thrown errors in a complex selector", function(){
// Given
const system = new System({
plugins: {
statePlugins: {
throw: {
selectors: {
func: (state, arg1) => system => {
throw new Error("this selector THROWS!")
}
}
}
}
}
})
expect(system.getSystem().throwSelectors.func).toNotThrow()
})
it("should encapsulate thrown errors in a wrapAction", function(){
// Given
const system = new System({
plugins: {
statePlugins: {
throw: {
actions: {
func: () => {
return {
type: "THROW_FUNC",
payload: "this original action does NOT throw"
}
}
},
wrapActions: {
func: (ori) => (...args) => {
throw new Error("this wrapAction UNRAVELS EVERYTHING!")
}
}
}
}
}
})
expect(system.getSystem().throwActions.func).toNotThrow()
})
it("should encapsulate thrown errors in a wrapSelector", function(){
// Given
const system = new System({
plugins: {
statePlugins: {
throw: {
selectors: {
func: (state, arg1) => {
return 123
}
},
wrapSelectors: {
func: (ori) => (...props) => {
return ori(...props)
}
}
}
}
}
})
expect(system.getSystem().throwSelectors.func).toNotThrow()
})
describe("components", function() {
it("should catch errors thrown inside of React Component Class render methods", function() {
// Given
// eslint-disable-next-line react/require-render-return
class BrokenComponent extends React.Component {
render() {
throw new Error("This component is broken")
}
}
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var Component = system.getSystem().getComponent("BrokenComponent")
const renderedComponent = render(<Component />)
// Then
expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
it("should catch errors thrown inside of pure component render methods", function() {
// Given
// eslint-disable-next-line react/require-render-return
class BrokenComponent extends PureComponent {
render() {
throw new Error("This component is broken")
}
}
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var Component = system.getSystem().getComponent("BrokenComponent")
const renderedComponent = render(<Component />)
// Then
expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
it("should catch errors thrown inside of stateless component functions", function() {
// Given
// eslint-disable-next-line react/require-render-return
let BrokenComponent = function BrokenComponent() { throw new Error("This component is broken") }
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var Component = system.getSystem().getComponent("BrokenComponent")
const renderedComponent = render(<Component />)
// Then
expect(renderedComponent.text().startsWith("😱 Could not render")).toEqual(true)
})
it("should catch errors thrown inside of container components", function() {
// Given
// eslint-disable-next-line react/require-render-return
class BrokenComponent extends React.Component {
render() {
throw new Error("This component is broken")
}
}
const system = new System({
plugins: [
ViewPlugin,
{
components: {
BrokenComponent
}
}
]
})
// When
var Component = system.getSystem().getComponent("BrokenComponent", true)
const renderedComponent = render(
<Provider store={system.getStore()}>
<Component />
</Provider>
)
// Then
expect(renderedComponent.text()).toEqual("😱 Could not render BrokenComponent, see the console.")
})
})
})
})
+23 -1
View File
@@ -18,7 +18,8 @@ import {
getAcceptControllingResponse,
createDeepLinkPath,
escapeDeepLinkPath,
sanitizeUrl
sanitizeUrl,
extractFileNameFromContentDispositionHeader
} from "core/utils"
import win from "core/window"
@@ -90,6 +91,26 @@ describe("utils", function() {
})
describe("extractFileNameFromContentDispositionHeader", function(){
it("should extract quoted filename", function(){
let cdHeader = "attachment; filename=\"file name.jpg\""
let expectedResult = "file name.jpg"
expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult)
})
it("should extract filename", function(){
let cdHeader = "attachment; filename=filename.jpg"
let expectedResult = "filename.jpg"
expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult)
})
it("should not extract filename and return null", function(){
let cdHeader = "attachment; no file name provided"
let expectedResult = null
expect(extractFileNameFromContentDispositionHeader(cdHeader)).toEqual(expectedResult)
})
})
describe("validateMaximum", function() {
let errorMessage = "Value must be less than Maximum"
@@ -238,6 +259,7 @@ describe("utils", function() {
it("doesn't return for valid guid", function() {
expect(validateGuid("8ce4811e-cec5-4a29-891a-15d1917153c1")).toBeFalsy()
expect(validateGuid("{8ce4811e-cec5-4a29-891a-15d1917153c1}")).toBeFalsy()
expect(validateGuid("8CE4811E-CEC5-4A29-891A-15D1917153C1")).toBeFalsy()
})
it("returns a message for invalid input'", function() {
+1
View File
@@ -67,6 +67,7 @@ module.exports = require("./make-webpack-config")(rules, {
publicPath: "/",
noInfo: true,
hot: true,
disableHostCheck: true, // for development within VMs
stats: {
colors: true
},