diff --git a/packages/app/package.json b/packages/app/package.json index e41444a7b4..e24ac9688c 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -5,6 +5,7 @@ "dependencies": { "@backstage/cli": "^0.1.1-alpha.2", "@backstage/core": "^0.1.1-alpha.2", + "@backstage/theme": "^0.1.1-alpha.2", "@backstage/plugin-home-page": "^0.1.1-alpha.2", "@backstage/plugin-welcome": "^0.1.1-alpha.2", "@material-ui/core": "^4.9.1", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 24dee65278..7f203db196 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -14,12 +14,14 @@ * limitations under the License. */ -import { CssBaseline, makeStyles, ThemeProvider } from '@material-ui/core'; import { - BackstageThemeLight, - BackstageThemeDark, - createApp, -} from '@backstage/core'; + CssBaseline, + makeStyles, + Theme, + ThemeProvider, +} from '@material-ui/core'; +import { BackstageThemeLight, BackstageThemeDark } from '@backstage/theme'; +import { createApp } from '@backstage/core'; import React, { FC } from 'react'; import { BrowserRouter as Router } from 'react-router-dom'; import Root from './components/Root'; @@ -51,13 +53,15 @@ app.registerApis(apis); app.registerPlugin(...Object.values(plugins)); const AppComponent = app.build(); +type T = typeof BackstageThemeLight | typeof BackstageThemeDark; + const App: FC<{}> = () => { useStyles(); const [theme, toggleTheme] = useThemeType( localStorage.getItem('theme') || 'auto', ); - let backstageTheme = BackstageThemeLight; + let backstageTheme: T = BackstageThemeLight; switch (theme) { case 'light': backstageTheme = BackstageThemeLight; @@ -82,7 +86,7 @@ const App: FC<{}> = () => { }; return ( - + diff --git a/packages/cli/config/eslint.js b/packages/cli/config/eslint.js index 81941b6fad..dbdb349274 100644 --- a/packages/cli/config/eslint.js +++ b/packages/cli/config/eslint.js @@ -61,7 +61,7 @@ module.exports = { }, }, { - files: ['**/*.test.*', '**/src/setupTests.*', '**/src/testUtils/**'], + files: ['**/*.test.*', '**/src/setupTests.*'], rules: { // Tests are allowed to import dev dependencies 'import/no-extraneous-dependencies': [ diff --git a/packages/cli/src/commands/plugin/rollup.config.ts b/packages/cli/src/commands/plugin/rollup.config.ts index d1f251665f..bc73a789ff 100644 --- a/packages/cli/src/commands/plugin/rollup.config.ts +++ b/packages/cli/src/commands/plugin/rollup.config.ts @@ -46,7 +46,6 @@ export default { json(), typescript({ include: `${paths.resolveTarget('src')}/**/*.{js,jsx,ts,tsx}`, - exclude: [paths.resolveTarget('src/testUtils/**')], }), ], } as RollupWatchOptions; diff --git a/packages/cli/templates/default-app/packages/app/src/App.tsx b/packages/cli/templates/default-app/packages/app/src/App.tsx index 14a07870b2..ec8d8d435a 100644 --- a/packages/cli/templates/default-app/packages/app/src/App.tsx +++ b/packages/cli/templates/default-app/packages/app/src/App.tsx @@ -1,5 +1,6 @@ import { CssBaseline, makeStyles, ThemeProvider } from '@material-ui/core'; -import { BackstageTheme, createApp } from '@backstage/core'; +import { createApp } from '@backstage/core'; +import { BackstageTheme } from '@backstage/theme'; import React, { FC } from 'react'; import { BrowserRouter as Router } from 'react-router-dom'; import * as plugins from './plugins'; diff --git a/packages/cli/templates/default-app/plugins/welcome/package.json.hbs b/packages/cli/templates/default-app/plugins/welcome/package.json.hbs index 1aa7f2c5c7..581f5e41ce 100644 --- a/packages/cli/templates/default-app/plugins/welcome/package.json.hbs +++ b/packages/cli/templates/default-app/plugins/welcome/package.json.hbs @@ -10,11 +10,12 @@ "test": "backstage-cli test" }, "devDependencies": { - "@backstage/core": "^{{version}}", "@backstage/cli": "^{{version}}", "@types/testing-library__jest-dom": "5.0.2" }, "dependencies": { - "@material-ui/lab": "4.0.0-alpha.45" + "@material-ui/lab": "4.0.0-alpha.45", + "@backstage/core": "^{{version}}", + "@backstage/theme": "^{{version}}" } } diff --git a/packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/WelcomePage.test.tsx b/packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/WelcomePage.test.tsx index 4b9b12913d..6d9268fadd 100644 --- a/packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/WelcomePage.test.tsx +++ b/packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/WelcomePage.test.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import WelcomePage from './WelcomePage'; import { ThemeProvider } from '@material-ui/core'; -import { BackstageTheme } from '@backstage/core'; +import { BackstageTheme } from '@backstage/theme'; describe('WelcomePage', () => { it('should render', () => { diff --git a/packages/cli/templates/default-plugin/package.json.hbs b/packages/cli/templates/default-plugin/package.json.hbs index 3fb02a992e..49d8d20d71 100644 --- a/packages/cli/templates/default-plugin/package.json.hbs +++ b/packages/cli/templates/default-plugin/package.json.hbs @@ -22,6 +22,7 @@ }, "peerDependencies": { "@backstage/core": "^{{version}}", + "@backstage/theme": "^{{version}}", "@material-ui/core": "^4.9.1", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", diff --git a/packages/cli/templates/default-plugin/src/components/ExampleComponent/ExampleComponent.test.tsx.hbs b/packages/cli/templates/default-plugin/src/components/ExampleComponent/ExampleComponent.test.tsx.hbs index 15db0863d2..80b97169bf 100644 --- a/packages/cli/templates/default-plugin/src/components/ExampleComponent/ExampleComponent.test.tsx.hbs +++ b/packages/cli/templates/default-plugin/src/components/ExampleComponent/ExampleComponent.test.tsx.hbs @@ -19,7 +19,7 @@ import { render } from '@testing-library/react'; import mockFetch from 'jest-fetch-mock'; import ExampleComponent from './ExampleComponent'; import { ThemeProvider } from '@material-ui/core'; -import { BackstageTheme } from '@backstage/core'; +import { BackstageTheme } from '@backstage/theme'; describe('ExampleComponent', () => { it('should render', () => { diff --git a/packages/core/package.json b/packages/core/package.json index 34ccbf865f..85054eba14 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -42,9 +42,14 @@ }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.2", + "@backstage/test-utils": "^0.1.1-alpha.2", + "@backstage/theme": "^0.1.1-alpha.2", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", "react-router": "^5.1.2" + }, + "peerDependencies": { + "@backstage/theme": "^0.1.1-alpha.2" } } diff --git a/packages/core/src/api/apis/ApiProvider.test.tsx b/packages/core/src/api/apis/ApiProvider.test.tsx index 20634f74af..5734899f68 100644 --- a/packages/core/src/api/apis/ApiProvider.test.tsx +++ b/packages/core/src/api/apis/ApiProvider.test.tsx @@ -19,7 +19,7 @@ import ApiProvider, { useApi, withApis } from './ApiProvider'; import ApiRef from './ApiRef'; import ApiRegistry from './ApiRegistry'; import { render } from '@testing-library/react'; -import { withLogCollector } from '../../testUtils'; +import { withLogCollector } from '@backstage/test-utils'; describe('ApiProvider', () => { type Api = () => string; diff --git a/packages/core/src/components/CircleProgress.test.js b/packages/core/src/components/CircleProgress.test.js index 7d4b294dc1..68e8f027c2 100644 --- a/packages/core/src/components/CircleProgress.test.js +++ b/packages/core/src/components/CircleProgress.test.js @@ -16,9 +16,9 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInThemedTestApp } from '../testUtils'; +import { COLORS } from '@backstage/theme'; +import { wrapInThemedTestApp } from '@backstage/test-utils'; import CircleProgress, { getProgressColor } from './CircleProgress'; -import { COLORS } from '../theme/BackstageTheme'; describe('', () => { it('renders without exploding', () => { diff --git a/packages/core/src/components/CircleProgress.tsx b/packages/core/src/components/CircleProgress.tsx index 6d30916c81..d5cd191b3d 100644 --- a/packages/core/src/components/CircleProgress.tsx +++ b/packages/core/src/components/CircleProgress.tsx @@ -15,12 +15,11 @@ */ import { makeStyles } from '@material-ui/core'; +import { BackstageTheme, COLORS } from '@backstage/theme'; import { Circle } from 'rc-progress'; import React, { FC } from 'react'; -import { COLORS } from '../theme/BackstageTheme'; -import { BackstageTheme } from '../theme/theme'; -const useStyles = makeStyles((theme: BackstageTheme) => ({ +const useStyles = makeStyles(theme => ({ root: { position: 'relative', lineHeight: 0, diff --git a/packages/core/src/components/HorizontalScrollGrid.test.js b/packages/core/src/components/HorizontalScrollGrid.test.js index 6838b2bfc7..d7f1e2387a 100644 --- a/packages/core/src/components/HorizontalScrollGrid.test.js +++ b/packages/core/src/components/HorizontalScrollGrid.test.js @@ -16,7 +16,7 @@ import React from 'react'; import { render, fireEvent } from '@testing-library/react'; -import { renderWithEffects, wrapInThemedTestApp } from '../testUtils'; +import { renderWithEffects, wrapInThemedTestApp } from '@backstage/test-utils'; import HorizontalScrollGrid from './HorizontalScrollGrid'; import { Grid } from '@material-ui/core'; diff --git a/packages/core/src/components/ProgressCard.test.js b/packages/core/src/components/ProgressCard.test.js index 4ebb869285..7357cab812 100644 --- a/packages/core/src/components/ProgressCard.test.js +++ b/packages/core/src/components/ProgressCard.test.js @@ -16,7 +16,7 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInThemedTestApp } from '../testUtils'; +import { wrapInThemedTestApp } from '@backstage/test-utils'; import ProgressCard from './ProgressCard'; diff --git a/packages/core/src/components/Status/Status.tsx b/packages/core/src/components/Status/Status.tsx index f6f331edce..d03dc52b6e 100644 --- a/packages/core/src/components/Status/Status.tsx +++ b/packages/core/src/components/Status/Status.tsx @@ -15,11 +15,11 @@ */ import { makeStyles } from '@material-ui/core'; +import { BackstageTheme } from '@backstage/theme'; import classNames from 'classnames'; import React, { FC } from 'react'; -import { BackstageTheme } from '../../theme/theme'; -const useStyles = makeStyles((theme: BackstageTheme) => ({ +const useStyles = makeStyles(theme => ({ status: { width: 12, height: 12, diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 73b0e33ddd..4472f57d40 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -24,10 +24,6 @@ export { default as HeaderLabel } from './layout/HeaderLabel'; export { default as InfoCard } from './layout/InfoCard'; export { default as ErrorBoundary } from './layout/ErrorBoundary'; export * from './layout/Sidebar'; -export { default as BackstageThemeLight } from './theme/BackstageThemeLight'; -export { default as BackstageTheme } from './theme/BackstageTheme'; -export { COLORS } from './theme/BackstageTheme'; -export { default as BackstageThemeDark } from './theme/BackstageThemeDark'; export { default as HorizontalScrollGrid } from './components/HorizontalScrollGrid'; export { default as ProgressCard } from './components/ProgressCard'; export { default as CircleProgress } from './components/CircleProgress'; diff --git a/packages/core/src/layout/ContentHeader/ContentHeader.test.tsx b/packages/core/src/layout/ContentHeader/ContentHeader.test.tsx index 50b4f921ac..1ab171bcf1 100644 --- a/packages/core/src/layout/ContentHeader/ContentHeader.test.tsx +++ b/packages/core/src/layout/ContentHeader/ContentHeader.test.tsx @@ -17,7 +17,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import ContentHeader from './ContentHeader'; -import { wrapInThemedTestApp } from '../../testUtils'; +import { wrapInThemedTestApp } from '@backstage/test-utils'; jest.mock('react-helmet', () => { return ({ defaultTitle }) =>
defaultTitle: {defaultTitle}
; diff --git a/packages/core/src/layout/ContentHeader/ContentHeader.tsx b/packages/core/src/layout/ContentHeader/ContentHeader.tsx index 0f83f54c25..61bea92639 100644 --- a/packages/core/src/layout/ContentHeader/ContentHeader.tsx +++ b/packages/core/src/layout/ContentHeader/ContentHeader.tsx @@ -21,9 +21,8 @@ import React, { ComponentType, Fragment, FC } from 'react'; import { Typography, makeStyles } from '@material-ui/core'; import Helmet from 'react-helmet'; -import { BackstageTheme } from '../../theme/theme'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ container: { width: '100%', display: 'flex', diff --git a/packages/core/src/layout/ErrorBoundary/ErrorBoundary.tsx b/packages/core/src/layout/ErrorBoundary/ErrorBoundary.tsx index 34a903480e..9e9d639548 100644 --- a/packages/core/src/layout/ErrorBoundary/ErrorBoundary.tsx +++ b/packages/core/src/layout/ErrorBoundary/ErrorBoundary.tsx @@ -17,7 +17,7 @@ import React, { ComponentClass, Component, SFC } from 'react'; type Props = { - slackChannel: string; + slackChannel?: string; onError?: (error: Error, errorInfo: string) => null; }; @@ -69,13 +69,14 @@ export default ErrorBoundary; type EProps = { error?: Error; errorInfo?: string; - slackChannel: string; + slackChannel?: string; }; const Error: SFC = ({ slackChannel }) => { return (
- Something went wrong here. Please contact {slackChannel} for help. + Something went wrong here.{' '} + {slackChannel && <>Please contact {slackChannel} for help.}
); }; diff --git a/packages/core/src/layout/Header/Header.test.tsx b/packages/core/src/layout/Header/Header.test.tsx index 5213fe1ac3..79d74791c8 100644 --- a/packages/core/src/layout/Header/Header.test.tsx +++ b/packages/core/src/layout/Header/Header.test.tsx @@ -16,8 +16,8 @@ import React from 'react'; import { render } from '@testing-library/react'; +import { wrapInThemedTestApp } from '@backstage/test-utils'; import Header from './Header'; -import { wrapInThemedTestApp } from '../../testUtils'; jest.mock('react-helmet', () => { return ({ defaultTitle }) =>
defaultTitle: {defaultTitle}
; diff --git a/packages/core/src/layout/Header/Header.tsx b/packages/core/src/layout/Header/Header.tsx index 5b3bb7ee60..6af4019d13 100644 --- a/packages/core/src/layout/Header/Header.tsx +++ b/packages/core/src/layout/Header/Header.tsx @@ -17,12 +17,13 @@ import React, { Fragment, ReactNode, CSSProperties, FC } from 'react'; import Helmet from 'react-helmet'; import { Typography, Tooltip, makeStyles } from '@material-ui/core'; +import { BackstageTheme } from '@backstage/theme'; + import { Theme } from '../Page/Page'; // import { Link } from 'shared/components'; -import { BackstageTheme } from '../../theme/theme'; import Waves from './Waves'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ header: { gridArea: 'pageHeader', padding: theme.spacing(3), diff --git a/packages/core/src/layout/HeaderActionMenu/HeaderActionMenu.test.tsx b/packages/core/src/layout/HeaderActionMenu/HeaderActionMenu.test.tsx index 3a32d9371e..17822228e8 100644 --- a/packages/core/src/layout/HeaderActionMenu/HeaderActionMenu.test.tsx +++ b/packages/core/src/layout/HeaderActionMenu/HeaderActionMenu.test.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { render, fireEvent } from '@testing-library/react'; -import { wrapInThemedTestApp, Keyboard } from '../../testUtils'; +import { wrapInThemedTestApp, Keyboard } from '@backstage/test-utils'; import HeaderActionMenu from './HeaderActionMenu'; describe('', () => { diff --git a/packages/core/src/layout/HeaderLabel/HeaderLabel.test.tsx b/packages/core/src/layout/HeaderLabel/HeaderLabel.test.tsx index 727c890e35..cbdfb3da80 100644 --- a/packages/core/src/layout/HeaderLabel/HeaderLabel.test.tsx +++ b/packages/core/src/layout/HeaderLabel/HeaderLabel.test.tsx @@ -16,8 +16,8 @@ import React from 'react'; import { render } from '@testing-library/react'; +import { wrapInThemedTestApp } from '@backstage/test-utils'; import HeaderLabel from './HeaderLabel'; -import { wrapInThemedTestApp } from '../../testUtils'; describe('', () => { it('should have a label', () => { diff --git a/packages/core/src/layout/HeaderLabel/HeaderLabel.tsx b/packages/core/src/layout/HeaderLabel/HeaderLabel.tsx index 56fcd01152..e2fd11ff15 100644 --- a/packages/core/src/layout/HeaderLabel/HeaderLabel.tsx +++ b/packages/core/src/layout/HeaderLabel/HeaderLabel.tsx @@ -16,9 +16,8 @@ import { Link, makeStyles, Typography } from '@material-ui/core'; import React, { FC } from 'react'; -import { BackstageTheme } from '../../theme/theme'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ root: { textAlign: 'left', margin: theme.spacing(2), diff --git a/packages/core/src/layout/InfoCard/BottomLink.test.tsx b/packages/core/src/layout/InfoCard/BottomLink.test.tsx index d240a232b7..f301de1c84 100644 --- a/packages/core/src/layout/InfoCard/BottomLink.test.tsx +++ b/packages/core/src/layout/InfoCard/BottomLink.test.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInTestApp } from '../../testUtils'; +import { wrapInTestApp } from '@backstage/test-utils'; import BottomLink from './BottomLink'; const minProps = { diff --git a/packages/core/src/layout/InfoCard/BottomLink.tsx b/packages/core/src/layout/InfoCard/BottomLink.tsx index 12eabbe753..6721eda0f1 100644 --- a/packages/core/src/layout/InfoCard/BottomLink.tsx +++ b/packages/core/src/layout/InfoCard/BottomLink.tsx @@ -26,9 +26,8 @@ import Box from '@material-ui/core/Box'; import grey from '@material-ui/core/colors/grey'; import ArrowIcon from '@material-ui/icons/ArrowForward'; import React, { FC } from 'react'; -import { BackstageTheme } from '../../theme/theme'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ root: { maxWidth: 'fit-content', padding: theme.spacing(2, 2, 2, 2.5), diff --git a/packages/core/src/layout/InfoCard/InfoCard.test.tsx b/packages/core/src/layout/InfoCard/InfoCard.test.tsx index 7d184d2f89..4d8221d5b8 100644 --- a/packages/core/src/layout/InfoCard/InfoCard.test.tsx +++ b/packages/core/src/layout/InfoCard/InfoCard.test.tsx @@ -16,7 +16,7 @@ import React from 'react'; import { render } from '@testing-library/react'; -import { wrapInTestApp } from '../../testUtils'; +import { wrapInTestApp } from '@backstage/test-utils'; import InfoCard from './InfoCard'; const minProps = { diff --git a/packages/core/src/layout/InfoCard/InfoCard.tsx b/packages/core/src/layout/InfoCard/InfoCard.tsx index 5b3ab1cfd1..10f9f60da0 100644 --- a/packages/core/src/layout/InfoCard/InfoCard.tsx +++ b/packages/core/src/layout/InfoCard/InfoCard.tsx @@ -26,9 +26,8 @@ import { } from '@material-ui/core'; import ErrorBoundary from '../ErrorBoundary/ErrorBoundary'; import BottomLink, { Props as BottomLinkProps } from './BottomLink'; -import { BackstageTheme } from '../../theme/theme'; -const useStyles = makeStyles(theme => ({ +const useStyles = makeStyles(theme => ({ header: { padding: theme.spacing(2, 2, 2, 2.5), }, diff --git a/packages/core/src/theme/theme.d.ts b/packages/core/src/theme/theme.d.ts deleted file mode 100644 index 7c9f552310..0000000000 --- a/packages/core/src/theme/theme.d.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2020 Spotify AB - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { Theme } from '@material-ui/core'; - -export type BackstageTheme = Theme & { - palette: { - status: { - ok: string; - warning: string; - error: string; - pending: string; - running: string; - background: string; - }; - border: string; - textVerySubtle: string; - textSubtle: string; - highlight: string; - errorBackground: string; - warningBackground: string; - infoBackground: string; - errorText: string; - infoText: string; - warningText: string; - linkHover: string; - link: string; - gold: string; - bursts: { - fontColor: string; - slackChannelText: string; - backgroundColor: { - default: string; - }; - }; - }; -}; diff --git a/packages/testUtils/.npmrc b/packages/testUtils/.npmrc new file mode 100644 index 0000000000..214c29d139 --- /dev/null +++ b/packages/testUtils/.npmrc @@ -0,0 +1 @@ +registry=https://registry.npmjs.org/ diff --git a/packages/testUtils/README.md b/packages/testUtils/README.md new file mode 100644 index 0000000000..46a2e2dab3 --- /dev/null +++ b/packages/testUtils/README.md @@ -0,0 +1,22 @@ +# @backstage/test-utils + +This package provides utilities that can be used to test plugins and apps for Backstage. + +## Installation + +Install the package via npm or yarn: + +```sh +$ npm install --save-dev @backstage/test-utils +``` + +or + +```sh +$ yarn add -D @backstage/test-utils +``` + +## Documentation + +- [Backstage Readme](https://github.com/spotify/backstage/blob/master/README.md) +- [Backstage Documentation](https://github.com/spotify/backstage/blob/master/docs/README.md) diff --git a/packages/testUtils/package.json b/packages/testUtils/package.json new file mode 100644 index 0000000000..96c8de5974 --- /dev/null +++ b/packages/testUtils/package.json @@ -0,0 +1,54 @@ +{ + "name": "@backstage/test-utils", + "description": "Utilities to test Backstage plugins and apps.", + "version": "0.1.1-alpha.2", + "private": false, + "publishConfig": { + "access": "public" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/spotify/backstage", + "directory": "packages/testUtils" + }, + "keywords": [ + "backstage" + ], + "license": "Apache-2.0", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts", + "scripts": { + "build:watch": "backstage-cli plugin:build --watch", + "build": "backstage-cli build-cache -- backstage-cli plugin:build", + "lint": "backstage-cli lint", + "test": "backstage-cli test" + }, + "devDependencies": { + "@backstage/cli": "^0.1.1-alpha.2", + "@backstage/core": "^0.1.1-alpha.2", + "@backstage/theme": "^0.1.1-alpha.2", + "@material-ui/core": "^4.9.1", + "@testing-library/jest-dom": "^4.2.4", + "@testing-library/react": "^9.3.2", + "@testing-library/user-event": "^7.1.2", + "@types/jest": "^24.0.0", + "@types/node": "^12.0.0", + "react": "^16.12.0", + "react-dom": "^16.12.0", + "react-router": "^5.1.2", + "react-router-dom": "^5.1.2" + }, + "peerDependencies": { + "@backstage/core": "^0.1.1-alpha.2", + "@backstage/theme": "^0.1.1-alpha.2", + "@material-ui/core": "^4.9.1", + "@testing-library/jest-dom": "^4.2.4", + "@testing-library/react": "^9.3.2", + "@testing-library/user-event": "^7.1.2", + "react": "^16.12.0", + "react-dom": "^16.12.0", + "react-router": "^5.1.2", + "react-router-dom": "^5.1.2" + } +} diff --git a/packages/testUtils/src/index.ts b/packages/testUtils/src/index.ts new file mode 100644 index 0000000000..43faf28a4a --- /dev/null +++ b/packages/testUtils/src/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export * from './testUtils'; diff --git a/packages/testUtils/src/setupTests.ts b/packages/testUtils/src/setupTests.ts new file mode 100644 index 0000000000..8925258421 --- /dev/null +++ b/packages/testUtils/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import '@testing-library/jest-dom/extend-expect'; diff --git a/packages/core/src/testUtils/Keyboard.js b/packages/testUtils/src/testUtils/Keyboard.js similarity index 100% rename from packages/core/src/testUtils/Keyboard.js rename to packages/testUtils/src/testUtils/Keyboard.js diff --git a/packages/core/src/testUtils/Keyboard.test.js b/packages/testUtils/src/testUtils/Keyboard.test.js similarity index 100% rename from packages/core/src/testUtils/Keyboard.test.js rename to packages/testUtils/src/testUtils/Keyboard.test.js diff --git a/packages/core/src/testUtils/index.js b/packages/testUtils/src/testUtils/index.tsx similarity index 59% rename from packages/core/src/testUtils/index.js rename to packages/testUtils/src/testUtils/index.tsx index 611633dcde..d9a4389ac8 100644 --- a/packages/core/src/testUtils/index.js +++ b/packages/testUtils/src/testUtils/index.tsx @@ -14,39 +14,52 @@ * limitations under the License. */ -import React from 'react'; +import React, { + ComponentType, + ReactNode, + FunctionComponent, + ReactElement, +} from 'react'; import { ThemeProvider } from '@material-ui/core'; - +import { act } from 'react-dom/test-utils'; +import { render, RenderResult } from '@testing-library/react'; import { MemoryRouter } from 'react-router'; import { Route } from 'react-router-dom'; - -import { V1 } from '../theme/BackstageTheme'; -import ErrorBoundary from '../layout/ErrorBoundary'; -import { act } from 'react-dom/test-utils'; -import { render } from '@testing-library/react'; +import { BackstageTheme } from '@backstage/theme'; export { default as Keyboard } from './Keyboard'; export { default as mockBreakpoint } from './mockBreakpoint'; export * from './logCollector'; -export function wrapInTestApp(Component, initialRouterEntries) { - const Wrapper = Component instanceof Function ? Component : () => Component; +export function wrapInTestApp( + Component: ComponentType | ReactNode, + initialRouterEntries: string[] = ['/'], +) { + let Wrapper: ComponentType; + if (Component instanceof Function) { + Wrapper = Component; + } else { + Wrapper = (() => Component) as FunctionComponent; + } return ( - - - - + + ); } -export function wrapInThemedTestApp(component, initialRouterEntries) { - const themed = {component}; +export function wrapInThemedTestApp( + component: ReactNode, + initialRouterEntries: string[] = ['/'], +) { + const themed = ( + {component} + ); return wrapInTestApp(themed, initialRouterEntries); } -export const wrapInTheme = (component, theme = V1) => ( +export const wrapInTheme = (component: ReactNode, theme = BackstageTheme) => ( {component} ); @@ -55,10 +68,13 @@ export const wrapInTheme = (component, theme = V1) => ( // cleaner, since act doesn't return the result of the evaluated function. // https://github.com/testing-library/react-testing-library/issues/281 // https://github.com/facebook/react/pull/14853 -export async function renderWithEffects(nodes) { - let value; - await act(async () => { - value = await render(nodes); +export async function renderWithEffects( + nodes: ReactElement, +): Promise { + let value: RenderResult; + await act(() => { + value = render(nodes); }); + // @ts-ignore return value; } diff --git a/packages/core/src/testUtils/logCollector.js b/packages/testUtils/src/testUtils/logCollector.js similarity index 100% rename from packages/core/src/testUtils/logCollector.js rename to packages/testUtils/src/testUtils/logCollector.js diff --git a/packages/core/src/testUtils/mockBreakpoint.ts b/packages/testUtils/src/testUtils/mockBreakpoint.ts similarity index 100% rename from packages/core/src/testUtils/mockBreakpoint.ts rename to packages/testUtils/src/testUtils/mockBreakpoint.ts diff --git a/packages/testUtils/tsconfig.json b/packages/testUtils/tsconfig.json new file mode 100644 index 0000000000..596e2cf729 --- /dev/null +++ b/packages/testUtils/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src"] +} diff --git a/packages/theme/.npmrc b/packages/theme/.npmrc new file mode 100644 index 0000000000..214c29d139 --- /dev/null +++ b/packages/theme/.npmrc @@ -0,0 +1 @@ +registry=https://registry.npmjs.org/ diff --git a/packages/theme/README.md b/packages/theme/README.md new file mode 100644 index 0000000000..a1b6f81f92 --- /dev/null +++ b/packages/theme/README.md @@ -0,0 +1,22 @@ +# @backstage/theme + +This package provides the extended Material UI Theme(s) that power Backstage. + +## Installation + +Install the package via npm or yarn: + +```sh +$ npm install --save @backstage/theme +``` + +or + +```sh +$ yarn add @backstage/theme +``` + +## Documentation + +- [Backstage Readme](https://github.com/spotify/backstage/blob/master/README.md) +- [Backstage Documentation](https://github.com/spotify/backstage/blob/master/docs/README.md) diff --git a/packages/theme/package.json b/packages/theme/package.json new file mode 100644 index 0000000000..6dfaaa8d3e --- /dev/null +++ b/packages/theme/package.json @@ -0,0 +1,33 @@ +{ + "name": "@backstage/theme", + "description": "material-ui theme for use with Backstage.", + "version": "0.1.1-alpha.2", + "private": false, + "publishConfig": { + "access": "public" + }, + "homepage": "https://backstage.io", + "repository": { + "type": "git", + "url": "https://github.com/spotify/backstage", + "directory": "packages/theme" + }, + "keywords": [ + "backstage" + ], + "license": "Apache-2.0", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts", + "scripts": { + "build:watch": "backstage-cli plugin:build --watch", + "build": "backstage-cli build-cache -- backstage-cli plugin:build", + "lint": "backstage-cli lint" + }, + "devDependencies": { + "@backstage/cli": "^0.1.1-alpha.2", + "@material-ui/core": "^4.9.1" + }, + "peerDependencies": { + "@material-ui/core": "^4.9.1" + } +} diff --git a/packages/core/src/theme/BackstageTheme.js b/packages/theme/src/BackstageTheme.ts similarity index 93% rename from packages/core/src/theme/BackstageTheme.js rename to packages/theme/src/BackstageTheme.ts index de4bbffca5..202bdbc08c 100644 --- a/packages/core/src/theme/BackstageTheme.js +++ b/packages/theme/src/BackstageTheme.ts @@ -18,6 +18,8 @@ import { createMuiTheme } from '@material-ui/core'; import { darken, lighten } from '@material-ui/core/styles/colorManipulator'; import { blue, yellow } from '@material-ui/core/colors'; +import { BackstageMuiTheme, BackstageMuiThemeOptions } from './types'; + export const COLORS = { PAGE_BACKGROUND: '#F8F8F8', DEFAULT_PAGE_THEME_COLOR: '#7C3699', @@ -37,7 +39,7 @@ export const COLORS = { }, }; -const extendedThemeConfig = { +const extendedThemeConfig: BackstageMuiThemeOptions = { props: { MuiGrid: { spacing: 2, @@ -49,6 +51,7 @@ const extendedThemeConfig = { palette: { background: { default: COLORS.PAGE_BACKGROUND, + // @ts-ignore informational: '#60a3cb', }, status: { @@ -66,6 +69,7 @@ const extendedThemeConfig = { default: COLORS.DEFAULT_PAGE_THEME_COLOR, }, }, + // @ts-ignore primary: { main: blue[500], }, @@ -115,7 +119,9 @@ const extendedThemeConfig = { }, }; -const createOverrides = theme => { +const createOverrides = ( + theme: BackstageMuiTheme, +): Partial => { return { overrides: { MuiTableRow: { @@ -211,7 +217,7 @@ const createOverrides = theme => { MuiButton: { text: { // Text buttons have less padding by default, but we want to keep the original padding - padding: null, + padding: undefined, }, }, MuiChip: { @@ -237,12 +243,15 @@ const createOverrides = theme => { }; }; -const extendedTheme = createMuiTheme(extendedThemeConfig); +const extendedTheme = createMuiTheme(extendedThemeConfig) as BackstageMuiTheme; // V1 theming // https://material-ui-next.com/customization/themes/ // For CSS it is advised to use JSS, see https://material-ui-next.com/customization/css-in-js/ -const BackstageTheme = { ...extendedTheme, ...createOverrides(extendedTheme) }; +const BackstageTheme: BackstageMuiTheme = { + ...extendedTheme, + ...createOverrides(extendedTheme), +}; // Temporary workaround for files incorrectly importing the theme directly export const V1 = BackstageTheme; diff --git a/packages/core/src/theme/BackstageThemeDark.js b/packages/theme/src/BackstageThemeDark.ts similarity index 94% rename from packages/core/src/theme/BackstageThemeDark.js rename to packages/theme/src/BackstageThemeDark.ts index b5562a50ba..b8b89c8f0a 100644 --- a/packages/core/src/theme/BackstageThemeDark.js +++ b/packages/theme/src/BackstageThemeDark.ts @@ -18,6 +18,8 @@ import { createMuiTheme } from '@material-ui/core'; import { darken, lighten } from '@material-ui/core/styles/colorManipulator'; import { blue, yellow } from '@material-ui/core/colors'; +import { BackstageMuiTheme, BackstageMuiThemeOptions } from './types'; + export const COLORS = { PAGE_BACKGROUND: '#282828', EFAULT_PAGE_THEME_COLOR: '#232323', @@ -38,7 +40,7 @@ export const COLORS = { }, }; -const extendedThemeConfig = { +const extendedThemeConfig: BackstageMuiThemeOptions = { props: { MuiGrid: { spacing: 2, @@ -50,6 +52,7 @@ const extendedThemeConfig = { palette: { background: { default: COLORS.PAGE_BACKGROUND, + // @ts-ignore informational: '#60a3cb', }, color: { @@ -71,6 +74,7 @@ const extendedThemeConfig = { default: COLORS.DEFAULT_PAGE_THEME_COLOR, }, }, + // @ts-ignore primary: { main: blue[500], }, @@ -120,13 +124,15 @@ const extendedThemeConfig = { }, }; -const createOverrides = theme => { +const createOverrides = (theme: BackstageMuiTheme): BackstageMuiTheme => { return { overrides: { + // @ts-ignore MuiCSSBaseline: { '@global': { body: { backgroundColor: theme.palette.background.default, + // @ts-ignore color: theme.palette.color.default, }, }, @@ -224,7 +230,7 @@ const createOverrides = theme => { MuiButton: { text: { // Text buttons have less padding by default, but we want to keep the original padding - padding: null, + padding: undefined, }, }, MuiChip: { @@ -250,7 +256,7 @@ const createOverrides = theme => { }; }; -const extendedTheme = createMuiTheme(extendedThemeConfig); +const extendedTheme = createMuiTheme(extendedThemeConfig) as BackstageMuiTheme; // V1 theming // https://material-ui-next.com/customization/themes/ @@ -262,4 +268,5 @@ const BackstageThemeDark = { // Temporary workaround for files incorrectly importing the theme directly export const V1 = BackstageThemeDark; + export default BackstageThemeDark; diff --git a/packages/core/src/theme/BackstageThemeLight.js b/packages/theme/src/BackstageThemeLight.ts similarity index 94% rename from packages/core/src/theme/BackstageThemeLight.js rename to packages/theme/src/BackstageThemeLight.ts index 4f44a0c2b2..14bc942910 100644 --- a/packages/core/src/theme/BackstageThemeLight.js +++ b/packages/theme/src/BackstageThemeLight.ts @@ -18,6 +18,8 @@ import { createMuiTheme } from '@material-ui/core'; import { darken, lighten } from '@material-ui/core/styles/colorManipulator'; import { blue, yellow } from '@material-ui/core/colors'; +import { BackstageMuiTheme, BackstageMuiThemeOptions } from './types'; + export const COLORS = { PAGE_BACKGROUND: '#F8F8F8', DEFAULT_PAGE_THEME_COLOR: '#7C3699', @@ -37,7 +39,7 @@ export const COLORS = { }, }; -const extendedThemeConfig = { +const extendedThemeConfig: BackstageMuiThemeOptions = { props: { MuiGrid: { spacing: 2, @@ -49,6 +51,7 @@ const extendedThemeConfig = { palette: { background: { default: COLORS.PAGE_BACKGROUND, + // @ts-ignore informational: '#60a3cb', }, color: { @@ -69,6 +72,7 @@ const extendedThemeConfig = { default: COLORS.DEFAULT_PAGE_THEME_COLOR, }, }, + // @ts-ignore primary: { main: blue[500], }, @@ -118,13 +122,17 @@ const extendedThemeConfig = { }, }; -const createOverrides = theme => { +const createOverrides = ( + theme: BackstageMuiTheme, +): Partial => { return { overrides: { + // @ts-ignore MuiCSSBaseline: { '@global': { body: { backgroundColor: theme.palette.background.default, + // @ts-ignore color: theme.palette.color.default, }, }, @@ -222,7 +230,7 @@ const createOverrides = theme => { MuiButton: { text: { // Text buttons have less padding by default, but we want to keep the original padding - padding: null, + padding: undefined, }, }, MuiChip: { @@ -248,7 +256,7 @@ const createOverrides = theme => { }; }; -const extendedTheme = createMuiTheme(extendedThemeConfig); +const extendedTheme = createMuiTheme(extendedThemeConfig) as BackstageMuiTheme; // V1 theming // https://material-ui-next.com/customization/themes/ @@ -260,4 +268,5 @@ const BackstageThemeLight = { // Temporary workaround for files incorrectly importing the theme directly export const V1 = BackstageThemeLight; + export default BackstageThemeLight; diff --git a/packages/theme/src/index.ts b/packages/theme/src/index.ts new file mode 100644 index 0000000000..136355dc37 --- /dev/null +++ b/packages/theme/src/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +export { default as BackstageThemeLight } from './BackstageThemeLight'; +export { default as BackstageThemeDark } from './BackstageThemeDark'; +export { default as BackstageTheme, COLORS } from './BackstageTheme'; diff --git a/packages/theme/src/types.ts b/packages/theme/src/types.ts new file mode 100644 index 0000000000..9a3e93c3a9 --- /dev/null +++ b/packages/theme/src/types.ts @@ -0,0 +1,56 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Theme, ThemeOptions } from '@material-ui/core'; + +export type BackstageMuiPalette = Theme['palette'] & { + status: { + ok: string; + warning: string; + error: string; + pending: string; + running: string; + background: string; + }; + border: string; + textVerySubtle: string; + textSubtle: string; + highlight: string; + errorBackground: string; + warningBackground: string; + infoBackground: string; + errorText: string; + infoText: string; + warningText: string; + linkHover: string; + link: string; + gold: string; + bursts: { + fontColor: string; + slackChannelText: string; + backgroundColor: { + default: string; + }; + }; +}; + +export interface BackstageMuiTheme extends Theme { + palette: BackstageMuiPalette; +} + +export interface BackstageMuiThemeOptions extends ThemeOptions { + palette: Partial; +} diff --git a/packages/theme/tsconfig.json b/packages/theme/tsconfig.json new file mode 100644 index 0000000000..596e2cf729 --- /dev/null +++ b/packages/theme/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src"] +} diff --git a/plugins/home-page/package.json b/plugins/home-page/package.json index 389133ccbe..73e208b737 100644 --- a/plugins/home-page/package.json +++ b/plugins/home-page/package.json @@ -13,6 +13,7 @@ "devDependencies": { "@backstage/cli": "^0.1.1-alpha.2", "@backstage/core": "^0.1.1-alpha.2", + "@backstage/theme": "^0.1.1-alpha.2", "@material-ui/core": "^4.9.1", "@material-ui/icons": "^4.9.1", "@testing-library/jest-dom": "^4.2.4", @@ -25,7 +26,8 @@ "react-dom": "^16.12.0" }, "peerDependencies": { - "@backstage/core": "^0.1.1-alpha.1", + "@backstage/core": "^0.1.1-alpha.2", + "@backstage/theme": "^0.1.1-alpha.2", "@material-ui/core": "^4.9.1", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", diff --git a/plugins/home-page/src/components/HomePage/HomePage.test.tsx b/plugins/home-page/src/components/HomePage/HomePage.test.tsx index 6b2c1bfd11..713f0afe1e 100644 --- a/plugins/home-page/src/components/HomePage/HomePage.test.tsx +++ b/plugins/home-page/src/components/HomePage/HomePage.test.tsx @@ -18,7 +18,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import HomePage from './HomePage'; import { ThemeProvider } from '@material-ui/core'; -import { BackstageTheme } from '@backstage/core'; +import { BackstageTheme } from '@backstage/theme'; describe('HomePage', () => { it('should render', () => { diff --git a/plugins/welcome/package.json b/plugins/welcome/package.json index 45fcd18be0..f4f33d6265 100644 --- a/plugins/welcome/package.json +++ b/plugins/welcome/package.json @@ -13,6 +13,7 @@ "devDependencies": { "@backstage/cli": "^0.1.1-alpha.2", "@backstage/core": "^0.1.1-alpha.2", + "@backstage/theme": "^0.1.1-alpha.2", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", "@testing-library/user-event": "^7.1.2", @@ -21,7 +22,8 @@ "@types/testing-library__jest-dom": "5.0.2" }, "peerDependencies": { - "@backstage/core": "^0.1.1-alpha.1", + "@backstage/core": "^0.1.1-alpha.2", + "@backstage/theme": "^0.1.1-alpha.2", "@material-ui/core": "^4.9.1", "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.45", diff --git a/plugins/welcome/src/components/WelcomePage/WelcomePage.test.tsx b/plugins/welcome/src/components/WelcomePage/WelcomePage.test.tsx index b4139e4ed3..9b78726f0a 100644 --- a/plugins/welcome/src/components/WelcomePage/WelcomePage.test.tsx +++ b/plugins/welcome/src/components/WelcomePage/WelcomePage.test.tsx @@ -18,12 +18,8 @@ import React from 'react'; import { render } from '@testing-library/react'; import WelcomePage from './WelcomePage'; import { ThemeProvider } from '@material-ui/core'; -import { - BackstageTheme, - ApiProvider, - ApiRegistry, - errorApiRef, -} from '@backstage/core'; +import { BackstageTheme } from '@backstage/theme'; +import { ApiProvider, ApiRegistry, errorApiRef } from '@backstage/core'; describe('WelcomePage', () => { it('should render', () => { diff --git a/yarn.lock b/yarn.lock index 73c20c3a2c..1f7b93d669 100644 --- a/yarn.lock +++ b/yarn.lock @@ -16924,7 +16924,7 @@ request@^2.85.0, request@^2.87.0, request@^2.88.0: tunnel-agent "^0.6.0" uuid "^3.3.2" -"request@github:cypress-io/request#b5af0d1fa47eec97ba980cde90a13e69a2afcd16": +request@cypress-io/request#b5af0d1fa47eec97ba980cde90a13e69a2afcd16: version "2.88.1" resolved "https://codeload.github.com/cypress-io/request/tar.gz/b5af0d1fa47eec97ba980cde90a13e69a2afcd16" dependencies: