diff --git a/app-config.yaml b/app-config.yaml index 22ca1fcaff..57349d213a 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -138,6 +138,11 @@ techdocs: dynatrace: baseUrl: https://your.dynatrace.instance.com +# Score-cards sample configuration. +scorecards: + jsonDataUrl: https://raw.githubusercontent.com/Oriflame/backstage-plugins/main/plugins/score-card/sample-data/ + wikiLinkTemplate: https://link-to-wiki/{id} + sentry: organization: my-company diff --git a/cypress/src/integration/plugins/score-card.spec.ts b/cypress/src/integration/plugins/score-card.spec.ts new file mode 100644 index 0000000000..5871a094e1 --- /dev/null +++ b/cypress/src/integration/plugins/score-card.spec.ts @@ -0,0 +1,83 @@ +/* + * Copyright 2021 The Backstage Authors + * + * 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 'os'; + +describe('score-card', () => { + describe('Score board', () => { + it('displays the score board based on sample data', () => { + cy.loginAsGuest(); + + cy.visit('/score-board'); + cy.screenshot({ capture: 'viewport' }); + + cy.contains('System scores overview').should('be.visible'); + cy.checkForErrors(); + cy.get('span:contains("1-2 of 2")').should('be.visible'); // beware, there is also a hidden

element + cy.contains('audio-playback').should('be.visible'); + cy.contains('team-c').should('be.visible'); + cy.contains('non-valid-system').should('be.visible'); + cy.contains('Name').should('be.visible'); + cy.contains('Date').should('be.visible'); + cy.contains('Code').should('be.visible'); + cy.contains('Documentation').should('be.visible'); + cy.contains('Operations').should('be.visible'); + cy.contains('Quality').should('be.visible'); + cy.contains('Security').should('be.visible'); + cy.contains('Total').should('be.visible'); + cy.contains('50 %').should('be.visible'); + cy.contains('75 %').should('be.visible'); + cy.log('navigating to score card detail for audio-playback'); + cy.get('a[data-id="audio-playback"]').should('be.visible').click(); + cy.screenshot({ capture: 'viewport' }); + + cy.url().should( + 'include', + '/catalog/default/System/audio-playback/score', + ); + cy.contains('Scoring').should('be.visible'); + cy.contains('Total score: 57 %').should('be.visible'); + cy.contains('Code').should('be.visible'); + cy.contains('90 %').should('be.visible'); + cy.contains('Documentation').should('be.visible'); + cy.contains('75 %').should('be.visible'); + cy.contains('Operations').should('be.visible'); + cy.contains('50 %').should('be.visible'); + cy.contains('Quality').should('be.visible'); + cy.contains('25 %').should('be.visible'); + cy.contains('Security'); + cy.contains('10 %').should('be.visible'); + cy.checkForErrors(); + + cy.log( + 'Clicking on button [>] that is first child of the element (td) with value=Code', + ); + cy.get('[value="Code"] > button:first-child').click(); + cy.checkForErrors(); + cy.screenshot({ capture: 'viewport' }); + + cy.log('Clicking on link for Code'); + cy.contains('hints: Gitflow: 100%').should('be.visible'); + cy.get('a[data-id="2157"]') + .should('be.visible') + .should( + 'have.attr', + 'href', + 'https://TBD/XXX/_wiki/wikis/XXX.wiki/2157', + ); + }); + }); +}); diff --git a/cypress/src/support/commands.ts b/cypress/src/support/commands.ts index 02723ffc90..62e21a5bef 100644 --- a/cypress/src/support/commands.ts +++ b/cypress/src/support/commands.ts @@ -118,3 +118,8 @@ Cypress.Commands.add('waitSectionTwoPage', () => { Cypress.Commands.add('waitHomePage', () => { cy.wait(['@entityMetadata', '@syncEntity', '@techdocsMetadata', '@homeHTML']); }); + +Cypress.Commands.add('checkForErrors', () => { + // when an error occurs there is a

with an "alert" role attribute. This can change ofc => we shall add also some positive ("when error occurs") test + cy.get('div[role="alert"]').should('not.exist'); +}); diff --git a/cypress/src/types.d.ts b/cypress/src/types.d.ts index 181b608a9b..dca22112e9 100644 --- a/cypress/src/types.d.ts +++ b/cypress/src/types.d.ts @@ -77,5 +77,10 @@ declare namespace Cypress { * @example cy.isNotInViewport */ isNotInViewport(element: string): Chainable; + /** + * Check if we have not caused error by our last action + * @example cy.checkForErrors + */ + checkForErrors(): Chainable; } } diff --git a/packages/app/package.json b/packages/app/package.json index 4181b036e9..e33092cf3d 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -67,6 +67,7 @@ "@material-ui/icons": "^4.9.1", "@material-ui/lab": "4.0.0-alpha.57", "@octokit/rest": "^19.0.3", + "@oriflame/backstage-plugin-score-card": "^0.5.1", "@roadiehq/backstage-plugin-buildkite": "^2.0.8", "@roadiehq/backstage-plugin-github-insights": "^2.0.5", "@roadiehq/backstage-plugin-github-pull-requests": "^2.2.7", diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx index 0b8107a216..d6b66d57a7 100644 --- a/packages/app/src/App.tsx +++ b/packages/app/src/App.tsx @@ -106,6 +106,7 @@ import { RequirePermission } from '@backstage/plugin-permission-react'; import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common'; import { PlaylistIndexPage } from '@backstage/plugin-playlist'; import { TwoColumnLayout } from './components/scaffolder/customScaffolderLayouts'; +import { ScoreBoardPage } from '@oriflame/backstage-plugin-score-card'; const app = createApp({ apis, @@ -273,6 +274,7 @@ const routes = ( } /> } /> } /> + } /> ); diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index 8b5f0932fb..0c142bafbd 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -51,6 +51,7 @@ import { import { MyGroupsSidebarItem } from '@backstage/plugin-org'; import GroupIcon from '@material-ui/icons/People'; import { SearchModal } from '../search/SearchModal'; +import Score from '@material-ui/icons/Score'; const useSidebarLogoStyles = makeStyles({ root: { @@ -120,6 +121,7 @@ export const Root = ({ children }: PropsWithChildren<{}>) => ( text="Cost Insights" /> + diff --git a/packages/app/src/components/catalog/EntityPage.tsx b/packages/app/src/components/catalog/EntityPage.tsx index c2f297a2d7..f7592eb0b9 100644 --- a/packages/app/src/components/catalog/EntityPage.tsx +++ b/packages/app/src/components/catalog/EntityPage.tsx @@ -144,6 +144,7 @@ import { EntityNewRelicDashboardCard, } from '@backstage/plugin-newrelic-dashboard'; import { EntityGoCdContent, isGoCdAvailable } from '@backstage/plugin-gocd'; +import { EntityScoreCardContent } from '@oriflame/backstage-plugin-score-card'; import React, { ReactNode, useMemo, useState } from 'react'; @@ -704,6 +705,13 @@ const systemPage = ( + + + + + + +