diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a029f0f5a5..7d127e79eb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,26 +29,26 @@ jobs: run: npm ci - name: CI Node Engine Check run: npm run ci:checkNodeEngine - # check-lint: - # name: Lint - # timeout-minutes: 15 - # runs-on: ubuntu-18.04 - # steps: - # - uses: actions/checkout@v2 - # - name: Use Node.js ${{ env.NODE_VERSION }} - # uses: actions/setup-node@v1 - # with: - # node-version: ${{ env.node-version }} - # - name: Cache Node.js modules - # uses: actions/cache@v2 - # with: - # path: ~/.npm - # key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }} - # restore-keys: | - # ${{ runner.os }}-node-${{ env.NODE_VERSION }}- - # - name: Install dependencies - # run: npm ci - # - run: npm run lint + check-lint: + name: Lint + timeout-minutes: 15 + runs-on: ubuntu-18.04 + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ env.NODE_VERSION }} + uses: actions/setup-node@v1 + with: + node-version: ${{ env.node-version }} + - name: Cache Node.js modules + uses: actions/cache@v2 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ env.NODE_VERSION }}-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node-${{ env.NODE_VERSION }}- + - name: Install dependencies + run: npm ci + - run: npm run lint check-circular: name: Circular Dependencies timeout-minutes: 5 @@ -147,6 +147,8 @@ jobs: - name: Install dependencies (Node >= 10) run: npm ci if: ${{ steps.node.outputs.node_major >= 10 }} + - name: Tests + run: npm test - name: Test bundles run: ./scripts/before_script.sh env: diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000000..a40157ac93 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,8 @@ +{ + "typeAcquisition": { + "include": [ + "jest" + ] + }, + "exclude": ["node_modules"] +} diff --git a/package-lock.json b/package-lock.json index 3f89dabc87..cd6b8ee59e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "parse-dashboard", - "version": "4.1.0-beta.1", + "version": "4.0.0-alpha.19", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -3751,6 +3751,95 @@ "@types/istanbul-lib-report": "*" } }, + "@types/jest": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.4.0.tgz", + "integrity": "sha512-gHl8XuC1RZ8H2j5sHv/JqsaxXkDDM9iDOgu0Wp8sjs4u/snb2PVehyWXJPr+ORA0RPpgw231mnutWI1+0hgjIQ==", + "dev": true, + "requires": { + "jest-diff": "^27.0.0", + "pretty-format": "^27.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "diff-sequences": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz", + "integrity": "sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==", + "dev": true + }, + "jest-diff": { + "version": "27.4.6", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.6.tgz", + "integrity": "sha512-zjaB0sh0Lb13VyPsd92V7HkqF6yKRH9vm33rwBt7rPYrpQvS1nCvlIy2pICbKta+ZjWngYLNn4cCK4nyZkjS/w==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^27.4.0", + "jest-get-type": "^27.4.0", + "pretty-format": "^27.4.6" + } + }, + "jest-get-type": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", + "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", + "dev": true + }, + "pretty-format": { + "version": "27.4.6", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz", + "integrity": "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + } + } + }, "@types/json-schema": { "version": "7.0.9", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", @@ -7353,6 +7442,7 @@ "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", "requires": { + "bytes": "3.1.1", "http-errors": "1.8.1", "iconv-lite": "0.4.24", "unpipe": "1.0.0" diff --git a/package.json b/package.json index 1ce538b6a6..e5750f9b00 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "parse-dashboard", - "version": "4.1.0-beta.1", + "version": "4.0.0-alpha.19", "repository": { "type": "git", "url": "https://github.com/ParsePlatform/parse-dashboard" @@ -89,6 +89,7 @@ "@semantic-release/github": "7.2.3", "@semantic-release/npm": "7.1.3", "@semantic-release/release-notes-generator": "9.0.3", + "@types/jest": "27.4.0", "all-node-versions": "8.0.0", "babel-eslint": "10.1.0", "babel-loader": "8.2.3", @@ -127,7 +128,6 @@ "build": "webpack --node-env=production --config webpack/production.config.js && webpack --config webpack/PIG.config.js", "test": "jest", "lint": "eslint . --ignore-path .gitignore --cache", - "pretest": "npm run lint", "generate": "node scripts/generate.js", "prepare": "webpack --config webpack/publish.config.js --progress", "start": "node ./Parse-Dashboard/index.js", @@ -148,6 +148,9 @@ "transform": { ".*": "/testing/preprocessor.js" }, + "moduleNameMapper": { + "\\.(css|less)$": "/testing/styleMock.js" + }, "unmockedModulePathPatterns": [ "react", "react-dom", diff --git a/release.config.js b/release.config.js index b6fec11c3d..e67b08526f 100644 --- a/release.config.js +++ b/release.config.js @@ -26,7 +26,7 @@ async function config() { // Get branch const branch = ref.split('/').pop(); console.log(`Running on branch: ${branch}`); - + // Set changelog file const changelogFile = `./changelogs/CHANGELOG_${branch}.md`; console.log(`Changelog file output to: ${changelogFile}`); @@ -96,7 +96,7 @@ async function config() { ['@semantic-release/github', { successComment: getReleaseComment(), labels: ['type:ci'], - releasedLabels: ['state:released<%= nextRelease.channel ? `-\${nextRelease.channel}` : "" %>'] + releasedLabels: ['state:released<%= nextRelease.channel ? `-${nextRelease.channel}` : "" %>'] }], ], }; diff --git a/src/components/Markdown/Markdown.react.js b/src/components/Markdown/Markdown.react.js index e3ba5dc3c6..7860b06860 100644 --- a/src/components/Markdown/Markdown.react.js +++ b/src/components/Markdown/Markdown.react.js @@ -6,7 +6,7 @@ * the root directory of this source tree. */ import CodeSnippet from 'components/CodeSnippet/CodeSnippet.react'; -import marked from 'marked'; +import { marked } from 'marked'; import PropTypes from 'lib/PropTypes'; import React from 'react'; import ReactDOMServer from 'react-dom/server'; diff --git a/src/components/Pill/Pill.react.js b/src/components/Pill/Pill.react.js index 81d7fe5818..ffef318f39 100644 --- a/src/components/Pill/Pill.react.js +++ b/src/components/Pill/Pill.react.js @@ -7,7 +7,7 @@ */ import React from 'react'; import styles from 'components/Pill/Pill.scss'; -import Icon from "components/Icon/Icon.react"; +import Icon from 'components/Icon/Icon.react'; //TODO: refactor, may want to move onClick outside or need to make onClick able to handle link/button a11y let Pill = ({ value, onClick, fileDownloadLink, followClick = false, shrinkablePill = false }) => ( @@ -15,7 +15,7 @@ let Pill = ({ value, onClick, fileDownloadLink, followClick = false, shrinkableP className={[ styles.pill, !followClick && onClick ? styles.action : void 0 - ].join(" ")} + ].join(' ')} onClick={!followClick && onClick ? onClick : null} > {value} diff --git a/src/components/PushPreview/PushPreview.react.js b/src/components/PushPreview/PushPreview.react.js index e654136278..8c1c7b90bb 100644 --- a/src/components/PushPreview/PushPreview.react.js +++ b/src/components/PushPreview/PushPreview.react.js @@ -5,8 +5,6 @@ * This source code is licensed under the license found in the LICENSE file in * the root directory of this source tree. */ -import PropTypes from 'lib/PropTypes'; -import ParseApp from 'lib/ParseApp'; import React from 'react'; import SegmentSelect from 'components/SegmentSelect/SegmentSelect.react'; import styles from 'components/PushPreview/PushPreview.scss'; diff --git a/src/components/Sidebar/Pin.react.js b/src/components/Sidebar/Pin.react.js index 035610fd00..21c4eb2d7f 100644 --- a/src/components/Sidebar/Pin.react.js +++ b/src/components/Sidebar/Pin.react.js @@ -1,7 +1,7 @@ -import React from "react"; +import React from 'react'; -import Icon from "components/Icon/Icon.react"; -import styles from "components/Sidebar/Sidebar.scss"; +import Icon from 'components/Icon/Icon.react'; +import styles from 'components/Sidebar/Sidebar.scss'; const Pin = ({ onClick }) => (
diff --git a/src/dashboard/Data/Browser/Browser.react.js b/src/dashboard/Data/Browser/Browser.react.js index 816c038e11..df711ebb44 100644 --- a/src/dashboard/Data/Browser/Browser.react.js +++ b/src/dashboard/Data/Browser/Browser.react.js @@ -402,7 +402,7 @@ class Browser extends DashboardView { if (name === 'objectId' || this.state.isUnique && name !== this.state.uniqueField) { return; } - if (!!required) { + if (required) { requiredCols.push(name); } if (className === '_User' && (name === 'username' || name === 'password')) { @@ -419,7 +419,7 @@ class Browser extends DashboardView { for (let idx = 0; idx < requiredCols.length; idx++) { const name = requiredCols[idx]; if (obj.get(name) == null) { - this.showNote("Please enter all required fields", true); + this.showNote('Please enter all required fields', true); this.setState({ markRequiredFieldRow: -1 }); @@ -461,7 +461,7 @@ class Browser extends DashboardView { if (msg) { msg = msg[0].toUpperCase() + msg.substr(1); } - obj.set(attr, prev); + obj.revert(); this.setState({ data: this.state.data }); this.showNote(msg, true); } @@ -506,7 +506,7 @@ class Browser extends DashboardView { if (name === 'objectId' || this.state.isUnique && name !== this.state.uniqueField) { return; } - if (!!required) { + if (required) { requiredCols.push(name); } if (className === '_User' && (name === 'username' || name === 'password')) { @@ -523,7 +523,7 @@ class Browser extends DashboardView { for (let idx = 0; idx < requiredCols.length; idx++) { const name = requiredCols[idx]; if (obj.get(name) == null) { - this.showNote("Please enter all required fields", true); + this.showNote('Please enter all required fields', true); this.setState({ markRequiredFieldRow: rowIndex }); diff --git a/src/dashboard/Data/Browser/BrowserToolbar.react.js b/src/dashboard/Data/Browser/BrowserToolbar.react.js index 418f837bd0..8079c48a41 100644 --- a/src/dashboard/Data/Browser/BrowserToolbar.react.js +++ b/src/dashboard/Data/Browser/BrowserToolbar.react.js @@ -326,7 +326,7 @@ let BrowserToolbar = ({ {editCloneRows && editCloneRows.length > 0 && ( diff --git a/src/dashboard/Data/Browser/DataBrowser.react.js b/src/dashboard/Data/Browser/DataBrowser.react.js index 8827b35dbb..962ba7e46c 100644 --- a/src/dashboard/Data/Browser/DataBrowser.react.js +++ b/src/dashboard/Data/Browser/DataBrowser.react.js @@ -257,6 +257,7 @@ export default class DataBrowser extends React.Component { getNextVisibleColumnIndex(distance = 1, min = 0, max = 0) { if (distance === 0) { return this.state.current.col; } let newIndex = this.state.current.col + distance; + // eslint-disable-next-line no-constant-condition while (true) { if (this.state.order[newIndex]?.visible) { return newIndex; } if (newIndex <= min) { return min; } diff --git a/src/dashboard/Data/Browser/ExportSelectedRowsDialog.react.js b/src/dashboard/Data/Browser/ExportSelectedRowsDialog.react.js index 1e4b5bf2db..9152d11662 100644 --- a/src/dashboard/Data/Browser/ExportSelectedRowsDialog.react.js +++ b/src/dashboard/Data/Browser/ExportSelectedRowsDialog.react.js @@ -27,7 +27,7 @@ export default class ExportSelectedRowsDialog extends React.Component { { it('has a default state', () => { const component = renderer.create(