diff --git a/.babelrc b/.babelrc index 71345abd2..4aa3c3cdd 100644 --- a/.babelrc +++ b/.babelrc @@ -6,5 +6,6 @@ } }], "@babel/preset-react" - ] + ], + "plugins": ["@babel/plugin-proposal-class-properties"] } diff --git a/jest.config.js b/jest.config.js index 940766a62..72fcd0b7a 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,6 +2,7 @@ const path = require('path'); module.exports = { testURL: 'http://localhost', + coverageReporters: ['json', 'text', 'lcov', 'clover'], // per https://github.com/facebook/jest/issues/9396#issuecomment-573328488 coverageThreshold: { global: { branches: 90, diff --git a/package-lock.json b/package-lock.json index e2e095d07..1f2db3db0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17654,6 +17654,11 @@ } } }, + "remark-breaks": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/remark-breaks/-/remark-breaks-1.0.3.tgz", + "integrity": "sha512-ip5hvJE8vsUJCGfgHaEJbf/JfO6KTZV+NBG68AWkEMhrjHW3Qh7EorED41mCt0FFSTrUDeRiNHovKO7cqgPZmw==" + }, "remove-trailing-separator": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz", diff --git a/package.json b/package.json index 60ca86fd6..320aef520 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,8 @@ }, "devDependencies": { "@babel/core": "^7.4.4", + "@babel/plugin-proposal-class-properties": "^7.5.5", + "@babel/plugin-proposal-object-rest-spread": "^7.6.2", "@babel/preset-env": "^7.4.4", "@babel/preset-react": "^7.0.0", "@readme/eslint-config": "^1.7.0", @@ -40,7 +42,7 @@ "lerna": "^3.14.1", "node-sass": "^4.12.0", "prettier": "^1.19.1", - "sass-loader": "^8.0.0", + "sass-loader": "^7.3.1", "style-loader": "^1.0.0", "terser-webpack-plugin": "^2.3.1", "webpack": "^4.41.0", @@ -51,9 +53,9 @@ "dependencies": { "babel-polyfill": "^6.26.0", "prop-types": "^15.7.2", - "react": "^16.4.2", - "react-dom": "^16.4.2", - "react-hot-loader": "^4.12.14", + "react": "^16.6.0", + "react-dom": "^16.6.0", + "react-hot-loader": "^3.1.3", "swagger2openapi": "^5.3.1", "whatwg-fetch": "^3.0.0" } diff --git a/packages/api-explorer/__tests__/ResponseSchema.test.jsx b/packages/api-explorer/__tests__/ResponseSchema.test.jsx index 6fec04bc6..054e03db6 100644 --- a/packages/api-explorer/__tests__/ResponseSchema.test.jsx +++ b/packages/api-explorer/__tests__/ResponseSchema.test.jsx @@ -36,13 +36,14 @@ test('selectedStatus should change state of selectedStatus', () => { test('should display response schema description', () => { const responseSchema = shallow(); - - expect( - responseSchema - .find('div.desc') - .first() - .text(), - ).toBe(props.operation.responses['200'].description); + const text = responseSchema + .find('div.desc') + .first() + .find('div.desc') + .find('p') + .first() + .text(); + expect(text).toBe(props.operation.responses['200'].description); }); test('should work if there are no responses', () => { diff --git a/packages/api-explorer/__tests__/ResponseSchemaBody.test.jsx b/packages/api-explorer/__tests__/ResponseSchemaBody.test.jsx index e97e7121e..0246e9931 100644 --- a/packages/api-explorer/__tests__/ResponseSchemaBody.test.jsx +++ b/packages/api-explorer/__tests__/ResponseSchemaBody.test.jsx @@ -259,7 +259,7 @@ test('should render markdown in the description', () => { mount() .find('a') .html(), - ).toBe('Description'); + ).toBe('Description'); }); test('should show "string" response type for a simple `string` schema', () => { diff --git a/packages/api-explorer/__tests__/block-types/ApiHeader.test.jsx b/packages/api-explorer/__tests__/block-types/ApiHeader.test.jsx deleted file mode 100644 index fa74d2994..000000000 --- a/packages/api-explorer/__tests__/block-types/ApiHeader.test.jsx +++ /dev/null @@ -1,29 +0,0 @@ -const React = require('react'); -const { shallow } = require('enzyme'); -const ApiHeader = require('../../src/block-types/ApiHeader'); - -const block = { - type: 'api-header', - data: { - title: 'This is header', - type: 'post', - }, -}; - -describe('ApiHeader', () => { - it('Api Header will render text in table header cells', () => { - const apiHeader = shallow(); - expect(apiHeader.find('h1').text()).toBe('This is header'); - }); - - it('should render with the type in a span', () => { - const apiHeader = shallow(); - expect(apiHeader.find(`span.type-${block.data.type}`)).toHaveLength(1); - }); - - it('should create an #id with the slug of the title', () => { - const apiHeader = shallow(); - expect(apiHeader.find(`span#this-is-header`)).toHaveLength(1); - expect(apiHeader.find(`#section-this-is-header`)).toHaveLength(1); - }); -}); diff --git a/packages/api-explorer/__tests__/block-types/CallOut.test.jsx b/packages/api-explorer/__tests__/block-types/CallOut.test.jsx deleted file mode 100644 index 470336f8f..000000000 --- a/packages/api-explorer/__tests__/block-types/CallOut.test.jsx +++ /dev/null @@ -1,94 +0,0 @@ -const React = require('react'); -const { shallow, mount } = require('enzyme'); -const CallOut = require('../../src/block-types/CallOut'); - -test('should render title', () => { - const block = { - data: { - type: 'info', - title: 'Callout', - }, - }; - const callout = mount(); - expect(callout.find('h3').text()).toBe('Callout'); -}); - -describe('icons', () => { - const icons = { - info: 'info-circle', - warning: 'exclamation-circle', - danger: 'exclamation-triangle', - success: 'check-square', - }; - - it('should render with title', () => { - Object.keys(icons).forEach(type => { - const className = icons[type]; - const block = { - data: { - type, - title: 'Callout', - }, - }; - expect(mount().find(`.fa-${className}`)).toHaveLength(1); - }); - }); - - it('should render without title', () => { - Object.keys(icons).forEach(type => { - const className = icons[type]; - const block = { - data: { - type, - }, - }; - expect(mount().find(`.noTitleIcon .fa-${className}`)).toHaveLength( - 1, - ); - }); - }); -}); - -test('should render nothing if no title and icon', () => { - const block = { - data: { - type: '', - }, - }; - const callout = mount(); - expect(callout.find('span').text()).toBe(''); -}); - -test('should render body', () => { - const block = { - data: { - type: 'info', - body: 'body', - }, - }; - - const callout = shallow(); - expect( - callout - .render() - .find('.callout-body') - .html(), - ).toMatchSnapshot(); -}); - -test('should render markdown in body', () => { - const block = { - data: { - type: 'info', - body: '# heading\n`test`', - }, - }; - - const callout = shallow(); - expect( - callout - .render() - .find('.callout-body') - .html(), - ).toMatchSnapshot(); -}); diff --git a/packages/api-explorer/__tests__/block-types/Code.test.jsx b/packages/api-explorer/__tests__/block-types/Code.test.jsx deleted file mode 100644 index 34a632187..000000000 --- a/packages/api-explorer/__tests__/block-types/Code.test.jsx +++ /dev/null @@ -1,143 +0,0 @@ -const React = require('react'); -const { mount } = require('enzyme'); -const Code = require('../../src/block-types/Code'); - -const block = { - type: 'code', - sidebar: undefined, - data: { - codes: [ - { - code: 'whjdwhjwejhkwhjk', - language: 'text', - status: 400, - name: 'test', - }, - { - code: 'var a = 1', - language: 'javascript', - }, - { - code: 'whjdwhjwejhkwhjk', - language: 'text', - name: 'test', - }, - ], - }, -}; - -const block3 = { - type: 'code', - sidebar: undefined, - data: { - codes: [ - { - code: 'whjdwhjwejhkwhjk', - language: 'text', - status: 400, - }, - ], - }, -}; - -const badBlock = { - type: 'code', - sidebar: undefined, - data: { - codes: { - code: { - code: 'whjdwhjwejhkwhjk', - language: 'text', - status: 400, - }, - }, - }, -}; - -const block2 = { - type: 'code', - sidebar: undefined, - data: { - codes: [ - { - code: 'var a = 1', - language: 'javascript', - }, - ], - }, -}; - -test('Code will render name if provided within em tag if codes has a status', () => { - const codeInput = mount(); - expect(codeInput.find('em').text()).toBe('test'); -}); - -test('Code will render status code within em tag', () => { - const codeInput = mount(); - expect(codeInput.find('em').text()).toBe('Bad Request'); -}); - -test('If codes array is not passed as an array expect empty array', () => { - const codeInput = mount(); - - expect(codeInput.find('span').text()).toBe(''); -}); - -test('Code will render language if name or status is not provided within a tag if codes has a status', () => { - const codeInput = mount(); - expect(codeInput.find('a').text()).toBe('JavaScript'); -}); - -test('Code will render label if provided within opts', () => { - const codeInput = mount(); - expect(codeInput.find('label').text()).toBe('label'); -}); - -test('Code should switch tabs', () => { - const codeInput = mount(); - const anchor = codeInput.find('li a').at(1); - anchor.simulate('click'); - expect(anchor.render().hasClass('active')).toBe(true); -}); - -test('should uppercase known languages', () => { - expect( - mount( - , - ) - .find('li a') - .text(), - ).toBe('HTTP'); -}); - -test('should pass through unknown languages', () => { - expect( - mount( - , - ) - .find('li a') - .text(), - ).toBe('unknown-language-somehow'); -}); diff --git a/packages/api-explorer/__tests__/block-types/Content.test.jsx b/packages/api-explorer/__tests__/block-types/Content.test.jsx deleted file mode 100644 index a51f82b7c..000000000 --- a/packages/api-explorer/__tests__/block-types/Content.test.jsx +++ /dev/null @@ -1,86 +0,0 @@ -const React = require('react'); -const fs = require('fs'); -const { mount } = require('enzyme'); -const Content = require('../../src/block-types/Content'); - -test('should output one of each block type', () => { - const body = fs.readFileSync(`${__dirname}/blocks.txt`, 'utf8'); - const content = mount(); - - ['textarea', 'html', 'embed', 'api-header', 'code', 'callout', 'parameters', 'image'].forEach( - type => { - expect(content.find(`.magic-block-${type}`)).toHaveLength(1); - }, - ); -}); - -const body = ` - [block:api-header] - { - "title": "This is cool header", - "sidebar": true - } - [/block] - [block:textarea] - { - "text": "This is text area" - } - [/block] -`; - -test('should output only left content if `isThreeColumn=left`', () => { - const content = mount(); - - expect(content.find('.magic-block-textarea')).toHaveLength(1); -}); - -test('should output only right content if `isThreeColumn=right`', () => { - const content = mount(); - - expect(content.find('.magic-block-api-header')).toHaveLength(1); -}); - -test('should make code not-dark if it is in the left column', () => { - const content = mount( - , - ); - - expect(content.html()).toContain('cm-s-neo'); -}); - -test('should make code `dark` if it is in right column', () => { - const content = mount( - , - ); - - expect(content.html()).toContain('cm-s-tomorrow-night'); -}); diff --git a/packages/api-explorer/__tests__/block-types/Embed.test.jsx b/packages/api-explorer/__tests__/block-types/Embed.test.jsx deleted file mode 100644 index aee2cf003..000000000 --- a/packages/api-explorer/__tests__/block-types/Embed.test.jsx +++ /dev/null @@ -1,65 +0,0 @@ -const React = require('react'); -const { shallow } = require('enzyme'); -const Embed = require('../../src/block-types/Embed'); - -describe('Embed', () => { - it('Embed will have src property if iframe is true', () => { - const block = { - type: 'embed', - data: { - html: false, - url: 'http://jsbin.com/fewilipowi/edit?js,output', - title: 'JS Bin', - favicon: 'http://static.jsbin.com/images/favicon.png', - image: 'http://static.jsbin.com/images/logo.png', - iframe: true, - }, - sidebar: undefined, - }; - const embedInput = shallow(); - expect(embedInput.find('iframe').prop('src')).toBe( - 'http://jsbin.com/fewilipowi/edit?js,output', - ); - // expect(embedInput.find('iframe').text()).toBe(''); - }); - - it('Embed will have no text property if iframe is false', () => { - const url = - ''; - const block = { - type: 'embed', - data: { - favicon: 'https://s.ytimg.com/yts/img/ringo/img/favicon-vfl8qSV2F.ico', - html: url, - image: 'https://i.ytimg.com/vi/jYjDqzZ4gjY/hqdefault.jpg', - sidebar: true, - title: 'White kids Watch me whip school Chorus', - url: 'https://www.youtube.com/watch?v=jYjDqzZ4gjY', - }, - sidebar: true, - }; - const embedInput = shallow(); - - expect(embedInput.find('span').text()).toBe(''); - }); - - it('Embed will have a and img tag if favicon is provided but iframe and html condition is false', () => { - const block = { - type: 'embed', - data: { - html: false, - url: 'http://jsbin.com/fewilipowi/edit?js,output', - favicon: 'http://static.jsbin.com/images/favicon.png', - image: 'http://static.jsbin.com/images/logo.png', - iframe: false, - width: '100%', - height: '300px', - }, - sidebar: undefined, - }; - const embedInput = shallow(); - expect(embedInput.find('strong').html()).toBe( - 'http://jsbin.com/fewilipowi/edit?js,output', - ); - }); -}); diff --git a/packages/api-explorer/__tests__/block-types/Html.test.jsx b/packages/api-explorer/__tests__/block-types/Html.test.jsx deleted file mode 100644 index 28ce0f30d..000000000 --- a/packages/api-explorer/__tests__/block-types/Html.test.jsx +++ /dev/null @@ -1,19 +0,0 @@ -const React = require('react'); -const { shallow } = require('enzyme'); -const Html = require('../../src/block-types/Html'); - -const block = { - type: 'html', - data: { - html: '

This is an html

', - }, - sidebar: undefined, -}; - -describe('Html', () => { - it('should display innerHtml', () => { - const htmlInput = shallow(); - expect(htmlInput.find('.magic-block-html')).toHaveLength(1); - expect(htmlInput.html()).toBe('

This is an html

'); - }); -}); diff --git a/packages/api-explorer/__tests__/block-types/Image.test.jsx b/packages/api-explorer/__tests__/block-types/Image.test.jsx deleted file mode 100644 index 0b9ae6e9c..000000000 --- a/packages/api-explorer/__tests__/block-types/Image.test.jsx +++ /dev/null @@ -1,60 +0,0 @@ -const React = require('react'); -const { shallow } = require('enzyme'); -const Image = require('../../src/block-types/Image'); - -describe('Image', () => { - it('Image has a tag with property href set to url', () => { - const block = { - type: 'image', - data: { - images: [ - { - image: [ - 'https://files.readme.io/924824e-fullsizeoutput_314.jpeg', - 'fullsizeoutput_314.jpeg', - 640, - 1136, - '#c8b396', - ], - }, - ], - }, - sidebar: undefined, - }; - const imageInput = shallow(); - - expect(imageInput.find('a').prop('href')).toBe( - 'https://files.readme.io/924824e-fullsizeoutput_314.jpeg', - ); - }); - - it('Image will render caption if given in props', () => { - const block = { - type: 'image', - data: { - images: [ - { - image: [ - 'https://files.readme.io/924824e-fullsizeoutput_314.jpeg', - 'fullsizeoutput_314.jpeg', - 640, - 1136, - '#c8b396', - ], - caption: 'doggo', - }, - ], - }, - sidebar: undefined, - }; - - const imageInput = shallow(); - - expect( - imageInput - .find('figcaption') - .render() - .text(), - ).toBe('doggo'); - }); -}); diff --git a/packages/api-explorer/__tests__/block-types/Parameters.test.jsx b/packages/api-explorer/__tests__/block-types/Parameters.test.jsx deleted file mode 100644 index 61abc9e3f..000000000 --- a/packages/api-explorer/__tests__/block-types/Parameters.test.jsx +++ /dev/null @@ -1,29 +0,0 @@ -const React = require('react'); -const { shallow } = require('enzyme'); -const Parameters = require('../../src/block-types/Parameters'); - -describe('Parameters', () => { - it('Parameters will render text in table', () => { - const block = { - type: 'parameters', - sidebar: undefined, - data: { - cols: 1, - rows: 1, - data: { - '0-0': 'arbitrary', - 'h-0': 'test', - }, - }, - }; - - const parametersInput = shallow(); - expect(parametersInput.find('div.th').text()).toBe('test'); - expect( - parametersInput - .find('div.td') - .render() - .text(), - ).toBe('arbitrary'); - }); -}); diff --git a/packages/api-explorer/__tests__/block-types/TextArea.test.jsx b/packages/api-explorer/__tests__/block-types/TextArea.test.jsx deleted file mode 100644 index 1d1764f69..000000000 --- a/packages/api-explorer/__tests__/block-types/TextArea.test.jsx +++ /dev/null @@ -1,14 +0,0 @@ -const React = require('react'); -const { shallow } = require('enzyme'); -const TextArea = require('../../src/block-types/TextArea'); - -describe('TextArea', () => { - it('Text area will output text', () => { - const block = { - type: 'textarea', - text: 'this is text', - }; - const textArea = shallow(