diff --git a/.changeset/cold-bags-admire.md b/.changeset/cold-bags-admire.md new file mode 100644 index 0000000000..98191958eb --- /dev/null +++ b/.changeset/cold-bags-admire.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-techdocs': patch +'@backstage/plugin-user-settings': patch +--- + +Add "data-testid" for e2e tests and fix techdocs entity not found error. diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0854635a2b..b637524a52 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -23,3 +23,4 @@ /.changeset/cost-insights-* @backstage/reviewers @backstage/silver-lining /.changeset/search-* @backstage/techdocs-core /.changeset/techdocs-* @backstage/techdocs-core +/cypress/src/integration/plugins/techdocs.spec.ts @backstage/techdocs-core diff --git a/.gitignore b/.gitignore index 57ad74c5cc..8c37280023 100644 --- a/.gitignore +++ b/.gitignore @@ -133,3 +133,6 @@ site # Sensitive credentials *-credentials.yaml + +# e2e tests +cypress/cypress/* diff --git a/app-config.yaml b/app-config.yaml index 3e2ab8471d..d2c8bf8074 100644 --- a/app-config.yaml +++ b/app-config.yaml @@ -262,7 +262,9 @@ catalog: # Backstage example groups and users - type: file target: ../catalog-model/examples/acme-corp.yaml - + # Backstage end-to-end tests of TechDocs + - type: file + target: ../../cypress/e2e-fixture.catalog.info.yaml scaffolder: # Use to customize default commit author info used when new components are created # defaultAuthor: diff --git a/cypress/.eslintrc.js b/cypress/.eslintrc.js index d7498649a0..a77de4a629 100644 --- a/cypress/.eslintrc.js +++ b/cypress/.eslintrc.js @@ -11,6 +11,7 @@ module.exports = { bundledDependencies: false, }, ], + 'jest/valid-expect': 'off', 'jest/expect-expect': 'off', 'no-restricted-syntax': 'off', }, diff --git a/cypress/cypress.json b/cypress/cypress.json index ebbbe59901..3ef3df8e65 100644 --- a/cypress/cypress.json +++ b/cypress/cypress.json @@ -2,7 +2,9 @@ "baseUrl": "http://localhost:7000", "integrationFolder": "./src/integration", "supportFile": "./src/support", - "fixturesFolder": "./src/fixures", + "fixturesFolder": "./src/fixtures", "pluginsFile": "./src/plugins", - "defaultCommandTimeout": 10000 + "defaultCommandTimeout": 10000, + "viewportHeight": 900, + "viewportWidth": 1440 } diff --git a/cypress/e2e-fixture.catalog.info.yaml b/cypress/e2e-fixture.catalog.info.yaml new file mode 100644 index 0000000000..31502e415d --- /dev/null +++ b/cypress/e2e-fixture.catalog.info.yaml @@ -0,0 +1,11 @@ +apiVersion: backstage.io/v1alpha1 +kind: Component +metadata: + name: techdocs-e2e-fixture + description: Used for end-to-end tests of TechDocs in Backstage. + annotations: + backstage.io/techdocs-ref: dir:./fixtures +spec: + type: service + lifecycle: experimental + owner: user:guest diff --git a/cypress/fixtures/docs/index.md b/cypress/fixtures/docs/index.md new file mode 100644 index 0000000000..d7ff14b46d --- /dev/null +++ b/cypress/fixtures/docs/index.md @@ -0,0 +1,3 @@ +# Home page + +This is a basic documentation used for end-to-end tests. diff --git a/cypress/fixtures/docs/sub-page-one.md b/cypress/fixtures/docs/sub-page-one.md new file mode 100644 index 0000000000..7c451efeb5 --- /dev/null +++ b/cypress/fixtures/docs/sub-page-one.md @@ -0,0 +1,109 @@ +# Sub-page 1 + +## Section 1.1 + +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! + +## Section 1.2 + +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! + +## Section 1.3 + +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! diff --git a/cypress/fixtures/docs/sub-page-three.md b/cypress/fixtures/docs/sub-page-three.md new file mode 100644 index 0000000000..e9a439ed98 --- /dev/null +++ b/cypress/fixtures/docs/sub-page-three.md @@ -0,0 +1,121 @@ +# Sub-page 3 + +## Section 3.1 + +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! + +## Section 3.2 + +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! + +### Sub-Section 3.2.1 + +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! + +### Sub-Section 3.2.2 + +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! + +## Section 3.3 + +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! diff --git a/cypress/fixtures/docs/sub-page-two.md b/cypress/fixtures/docs/sub-page-two.md new file mode 100644 index 0000000000..eb2344e9c3 --- /dev/null +++ b/cypress/fixtures/docs/sub-page-two.md @@ -0,0 +1,146 @@ +# Sub-page 2 + +## Section 2.1 + +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! + +## Section 2.2 + +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! + +### Sub-Section 2.2.1 + +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! + +### Sub-Section 2.2.2 + +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! + +## Section 2.3 + +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! +To next page! + +[Link to Section 1.1](sub-page-one.md#section-11) diff --git a/cypress/fixtures/mkdocs.yml b/cypress/fixtures/mkdocs.yml new file mode 100644 index 0000000000..2362fab898 --- /dev/null +++ b/cypress/fixtures/mkdocs.yml @@ -0,0 +1,10 @@ +site_name: e2e Fixture Documentation +site_description: Documentation used for end-to-end tests of TechDocs in Backstage. +nav: + - Home: index.md + - Sub-page 1: sub-page-one.md + - Sub-page 2: sub-page-two.md + - Nested Sub-pages: + - Sub-page 3: sub-page-three.md +plugins: + - techdocs-core diff --git a/cypress/src/integration/integrations.ts b/cypress/src/integration/integrations.spec.ts similarity index 100% rename from cypress/src/integration/integrations.ts rename to cypress/src/integration/integrations.spec.ts diff --git a/cypress/src/integration/catalog.ts b/cypress/src/integration/plugins/catalog.spec.ts similarity index 100% rename from cypress/src/integration/catalog.ts rename to cypress/src/integration/plugins/catalog.spec.ts diff --git a/cypress/src/integration/plugins/techdocs.spec.ts b/cypress/src/integration/plugins/techdocs.spec.ts new file mode 100644 index 0000000000..0edd7b15ff --- /dev/null +++ b/cypress/src/integration/plugins/techdocs.spec.ts @@ -0,0 +1,188 @@ +/* + * 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 'os'; + +describe('TechDocs', () => { + beforeEach(() => { + cy.loginAsGuest(); + cy.mockSockJSNode(); + cy.interceptTechDocsAPICalls(); + }); + + describe('Navigating to TechDocs', () => { + it('should navigate to the TechDocs home page via the primary navigation bar', () => { + cy.visit('/'); + cy.wait(500); + + cy.get('[data-testid="sidebar-root"]') + .get('div') + .get('a[href="/docs"]') + .click(); + + cy.contains('Documentation'); + }); + + it('should navigate to the TechDocs home page from the URL', () => { + cy.visit('/docs'); + cy.wait(500); + + cy.contains('Documentation'); + }); + + it('should navigate to a specific TechDocs entity from the "Overview" tab', () => { + cy.visit('/docs'); + cy.contains('techdocs-e2e-fixture') + .parents() + .eq(2) + .contains('Read Docs') + .click(); + + cy.location().should(loc => { + expect(loc.pathname).to.eq( + '/docs/default/Component/techdocs-e2e-fixture', + ); + }); + }); + + it('should navigate to a specific TechDocs entity page from a URL', () => { + cy.visit('/docs/default/Component/techdocs-e2e-fixture'); + cy.waitHomePage(); + + cy.contains('e2e Fixture Documentation'); + cy.contains( + 'Documentation used for end-to-end tests of TechDocs in Backstage.', + ); + cy.getTechDocsShadowRoot().contains('Home page'); + }); + + it('should navigate to a specific TechDocs section from a URL', () => { + cy.visit('/docs/default/Component/techdocs-e2e-fixture/sub-page-two'); + cy.waitSectionTwoPage(); + + cy.window().its('scrollY').should('equal', 0); + + cy.getTechDocsShadowRoot().within(() => { + cy.contains('Sub-page 2'); + }); + }); + + it('should navigate to a specific TechDocs fragment from a URL', () => { + cy.visit( + '/docs/default/Component/techdocs-e2e-fixture/sub-page-two#section-23', + ); + cy.waitSectionTwoPage(); + + // This is used to test the post-render behavior of the techdocs Reader + cy.wait(500); + + cy.getTechDocsShadowRoot().within(() => { + cy.isInViewport('#section-23'); + }); + }); + + it('should navigate to a wrong TechDocs entity page from a URL', () => { + cy.visit('/docs/default/Component/wrong-component'); + + cy.get('[data-testid=error]').should('be.visible'); + }); + }); + + describe('Navigating within TechDocs', () => { + it('should navigate to a specific TechDocs page via the navigation bar', () => { + cy.visit('/docs/default/Component/techdocs-e2e-fixture'); + cy.waitHomePage(); + + cy.getTechDocsShadowRoot().within(() => { + cy.getTechDocsNavigation() + .find('> div > div > [data-md-level="0"] > ul > li:nth-child(2) > a') + .click(); + cy.contains('Sub-page 1'); + cy.window().its('scrollY').should('eq', 0); + }); + }); + + describe('Navigating within a TechDocs page', () => { + beforeEach(() => { + cy.visit('/docs/default/Component/techdocs-e2e-fixture/sub-page-two'); + cy.waitSectionTwoPage(); + }); + it('should navigate to a specific fragment within the page via the table of contents - Level 1', () => { + return cy.getTechDocsShadowRoot().within(() => { + // Section 3 + cy.getTechDocsTableOfContents().within(() => { + cy.get('> div > div > nav > ul > li:nth-child(3) > a').click(); + }); + + cy.isInViewport('#section-23'); + }); + }); + + it('should navigate to a specific fragment within the page via the table of contents - Level 2', () => { + return cy.getTechDocsShadowRoot().within(() => { + cy.isNotInViewport('#sub-section-222'); + // Section 2.2 + cy.getTechDocsTableOfContents() + .find( + '> div > div > nav > ul > li:nth-child(2) > nav > ul > li:nth-child(2) > a', + ) + .click(); + + cy.isInViewport('#sub-section-222'); + }); + }); + + it('should navigate to a specific TechDocs page fragment from a link', () => { + return cy.getTechDocsShadowRoot().within(() => { + cy.get('.md-content > article') + .contains('Link to Section 1.1') + .click(); + + cy.location().should(loc => { + expect(loc.pathname).to.eq( + '/docs/default/Component/techdocs-e2e-fixture/sub-page-one/', + ); + expect(loc.hash).to.eq('#section-11'); + }); + }); + }); + + it('should navigate to the next page within a TechDocs entity', () => { + return cy.getTechDocsShadowRoot().within(() => { + cy.get('.md-footer-nav__link--next').click(); + + cy.location().should(loc => { + expect(loc.pathname).to.eq( + '/docs/default/Component/techdocs-e2e-fixture/sub-page-three/', + ); + }); + }); + }); + + it('should navigate to the previous page within a TechDocs entity', () => { + return cy.getTechDocsShadowRoot().within(() => { + cy.get('.md-footer-nav__link--prev').click(); + + cy.location().should(loc => { + expect(loc.pathname).to.eq( + '/docs/default/Component/techdocs-e2e-fixture/sub-page-one/', + ); + }); + }); + }); + }); + }); +}); diff --git a/cypress/src/integration/user/login.spec.ts b/cypress/src/integration/user/login.spec.ts new file mode 100644 index 0000000000..25be6e8d4b --- /dev/null +++ b/cypress/src/integration/user/login.spec.ts @@ -0,0 +1,31 @@ +/* + * 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 'os'; + +describe('Login', () => { + it('should render the login page', () => { + cy.visit('/'); + cy.contains('Select a sign-in method'); + }); + + it('should be able to login', () => { + cy.get('button').contains('Enter').click(); + cy.url().should('include', '/catalog'); + + cy.contains('artist-lookup'); + }); +}); diff --git a/cypress/src/integration/user/logout.spec.ts b/cypress/src/integration/user/logout.spec.ts new file mode 100644 index 0000000000..2d37cb63e5 --- /dev/null +++ b/cypress/src/integration/user/logout.spec.ts @@ -0,0 +1,35 @@ +/* + * 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 'os'; + +describe('Logout', () => { + before(() => { + cy.loginAsGuest(); + }); + it('should be able to logout', () => { + cy.visit('/settings'); + cy.get('[data-testid="user-settings-menu"]').click(); + return cy + .get('[data-testid="sign-out"]') + .click() + .then(() => { + return expect( + localStorage.getItem('@backstage/core:SignInPage:provider'), + ).to.be.null; + }); + }); +}); diff --git a/cypress/src/support/commands.ts b/cypress/src/support/commands.ts new file mode 100644 index 0000000000..3c8456fcbd --- /dev/null +++ b/cypress/src/support/commands.ts @@ -0,0 +1,116 @@ +/* + * Copyright 2021 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. + */ +/* eslint-disable jest/no-standalone-expect */ +/// +import 'os'; + +Cypress.Commands.add('loginAsGuest', () => { + cy.visit('/', { + onLoad: (win: Window) => + win.localStorage.setItem('@backstage/core:SignInPage:provider', 'guest'), + }); +}); + +Cypress.Commands.add('getTechDocsShadowRoot', () => { + cy.get('[data-testid="techdocs-content-shadowroot"]').shadow(); +}); + +Cypress.Commands.add('isNotInViewport', element => { + cy.get(element).then($el => { + const bottom = Cypress.config(`viewportHeight`); + const rect = $el[0].getBoundingClientRect(); + + if (bottom) { + expect(rect.top).to.be.greaterThan(bottom); + expect(rect.bottom).to.be.greaterThan(bottom); + expect(rect.top).to.be.greaterThan(bottom); + expect(rect.bottom).to.be.greaterThan(bottom); + } + }); +}); + +Cypress.Commands.add('isInViewport', element => { + cy.get(element).then($el => { + const bottom = Cypress.config(`viewportHeight`); + const rect = $el[0].getBoundingClientRect(); + + if (bottom) { + expect(rect.top).not.to.be.greaterThan(bottom); + expect(rect.bottom).not.to.be.greaterThan(bottom); + expect(rect.top).not.to.be.greaterThan(bottom); + expect(rect.bottom).not.to.be.greaterThan(bottom); + } + }); +}); + +Cypress.Commands.add('getTechDocsTableOfContents', () => { + cy.get('[data-md-component="toc"]'); +}); + +Cypress.Commands.add('getTechDocsNavigation', () => { + cy.get('[data-md-component="navigation"]'); +}); + +Cypress.Commands.add('mockSockJSNode', () => { + cy.intercept('GET', '**/sockjs-node/info**', { + body: { + websocket: true, + origins: ['*:*'], + cookie_needed: false, + entropy: 2882389500, + }, + }); +}); + +Cypress.Commands.add('interceptTechDocsAPICalls', () => { + cy.intercept( + 'GET', + '**/techdocs/metadata/entity/default/Component/techdocs-e2e-fixture', + ).as('entityMetadata'); + + cy.intercept( + 'GET', + '**/techdocs/metadata/techdocs/default/Component/techdocs-e2e-fixture', + ).as('techdocsMetadata'); + + cy.intercept( + 'GET', + '**/techdocs/sync/default/Component/techdocs-e2e-fixture', + ).as('syncEntity'); + + cy.intercept( + 'GET', + '**/techdocs/static/docs/default/Component/techdocs-e2e-fixture/sub-page-two/index.html', + ).as('sectionTwoHTML'); + + cy.intercept( + 'GET', + '**/techdocs/static/docs/default/Component/techdocs-e2e-fixture/index.html', + ).as('homeHTML'); +}); + +Cypress.Commands.add('waitSectionTwoPage', () => { + cy.wait([ + '@entityMetadata', + '@syncEntity', + '@techdocsMetadata', + '@sectionTwoHTML', + ]); +}); + +Cypress.Commands.add('waitHomePage', () => { + cy.wait(['@entityMetadata', '@syncEntity', '@techdocsMetadata', '@homeHTML']); +}); diff --git a/cypress/src/support/index.ts b/cypress/src/support/index.ts index ebfcb04d03..6d1051a793 100644 --- a/cypress/src/support/index.ts +++ b/cypress/src/support/index.ts @@ -14,12 +14,4 @@ * limitations under the License. */ /// - -Cypress.Commands.add('loginAsGuest', () => { - cy.visit('/', { - onLoad: (win: Window) => - win.localStorage.setItem('@backstage/core:SignInPage:provider', 'guest'), - }); -}); - -export {}; +import './commands'; diff --git a/cypress/src/types.d.ts b/cypress/src/types.d.ts index fff4fe29e4..838f5571ed 100644 --- a/cypress/src/types.d.ts +++ b/cypress/src/types.d.ts @@ -22,5 +22,55 @@ declare namespace Cypress { * @example cy.loginAsGuests */ loginAsGuest(): Chainable; + /** + * Get the TechDocs shadow root element + * @example cy.getTechDocsShadowRoot + */ + getTechDocsShadowRoot(): Chainable; + /** + * Mock TechDocs backend API + * @example cy.mockTechDocs + */ + mockTechDocs(): void; + /** + * Get the TechDocs table of contents element + * @example cy.getTechDocsShadowRoot + */ + getTechDocsTableOfContents(): Chainable; + /** + * Get the TechDocs navigation element + * @example cy.getTechDocsNavigation + */ + getTechDocsNavigation(): Chainable; + /** + * Intercept the TechDocs API calls + * @example cy.interceptTechDocsAPICalls + */ + interceptTechDocsAPICalls(): Chainable; + /** + * Mock SockJS-Node call + * @example cy.mockSockJSNode + */ + mockSockJSNode(): Chainable; + /** + * Wait TechDocs API response for home page + * @example cy.waitHomePage + */ + waitHomePage(): Chainable; + /** + * Wait TechDocs API response for Section 2 page + * @example cy.waitSectionTwoPage + */ + waitSectionTwoPage(): Chainable; + /** + * Check if the element is in viewport + * @example cy.isInViewport + */ + isInViewport(element: string): Chainable; + /** + * Check if the element is not in viewport + * @example cy.isNotInViewport + */ + isNotInViewport(element: string): Chainable; } } diff --git a/packages/core-components/src/layout/ErrorPage/ErrorPage.tsx b/packages/core-components/src/layout/ErrorPage/ErrorPage.tsx index f4b2960f96..87eebdb729 100644 --- a/packages/core-components/src/layout/ErrorPage/ErrorPage.tsx +++ b/packages/core-components/src/layout/ErrorPage/ErrorPage.tsx @@ -57,7 +57,11 @@ export function ErrorPage(props: IErrorPageProps) { - + ERROR {status}: {statusMessage} diff --git a/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx b/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx index 0fe3cd967e..3468439ade 100644 --- a/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx +++ b/packages/core-components/src/layout/HeaderTabs/HeaderTabs.tsx @@ -88,6 +88,7 @@ export function HeaderTabs(props: HeaderTabsProps) { {tabs.map((tab, index) => ( Read Docs diff --git a/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx b/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx index 9975db6435..9400ca3205 100644 --- a/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx +++ b/plugins/techdocs/src/home/components/TechDocsCustomHome.tsx @@ -108,7 +108,7 @@ const CustomPanel = ({ ) : null}
- +
); @@ -182,7 +182,7 @@ export const TechDocsCustomHome = ({ label, }))} /> - + {currentTabConfig.panels.map((config, index) => ( { return Promise.resolve(undefined); }, [kind, namespace, name, techdocsApi, documentReady]); - const { value: entityMetadataValue } = useAsync(() => { - return techdocsApi.getEntityMetadata({ kind, namespace, name }); - }, [kind, namespace, name, techdocsApi]); + const { value: entityMetadataValue, error: entityMetadataError } = + useAsync(() => { + return techdocsApi.getEntityMetadata({ kind, namespace, name }); + }, [kind, namespace, name, techdocsApi]); const onReady = useCallback(() => { setDocumentReady(true); }, [setDocumentReady]); + if (entityMetadataError) { + return ; + } + return ( { return ( <> - + - identityApi.signOut()}> + identityApi.signOut()}> diff --git a/scripts/check-docs-quality.js b/scripts/check-docs-quality.js index 4a07aeb3bd..3352596890 100755 --- a/scripts/check-docs-quality.js +++ b/scripts/check-docs-quality.js @@ -42,6 +42,7 @@ const getFilesToLint = () => { // Note this ignore list only applies locally, CI runs `.github/workflows/docs-quality-checker.yml` const ignored = ['', 'ADOPTERS.md', 'OWNERS.md']; + return execSync(command, { stdio: ['ignore', 'pipe', 'inherit'], })