Merge pull request #20157 from backstage/rugvip/playwright
replace Cypress with Playwright
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/e2e-test-utils': minor
|
||||
---
|
||||
|
||||
Initial release.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@techdocs/cli': patch
|
||||
---
|
||||
|
||||
Restructured tests.
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
'@backstage/create-app': patch
|
||||
---
|
||||
|
||||
The E2E test setup based on Cypress has been replaced with one based on [Playwright](https://playwright.dev/). Migrating existing apps is not required as this is a standalone setup, only do so if you also want to switch from Cypress to Playwright.
|
||||
|
||||
The scripts to run the E2E tests have been removed from `packages/app/package.json`, as they are now instead run from the root. Instead, a new script has been added to the root `package.json`, `yarn test:e2e`, which runs the E2E tests in development mode, unless `CI` is set in the environment.
|
||||
|
||||
The Playwright setup uses utilities from the new `@backstage/e2e-test-utils` package to find and include all packages in the monorepo that have an `e2e-tests` folder.
|
||||
@@ -2,7 +2,6 @@
|
||||
.yarn/cache
|
||||
.yarn/install-state.gz
|
||||
docs
|
||||
cypress
|
||||
microsite
|
||||
node_modules
|
||||
packages/*/src
|
||||
|
||||
@@ -9,3 +9,4 @@
|
||||
**/microsite/**
|
||||
**/templates/**
|
||||
**/sample-templates/**
|
||||
playwright.config.ts
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
yarn.lock @backstage/maintainers @backstage-service
|
||||
*/yarn.lock @backstage/maintainers @backstage-service
|
||||
/.changeset/*.md
|
||||
/cypress/src/integration/plugins/techdocs.spec.ts @backstage/techdocs-maintainers
|
||||
/docs/assets/search @backstage/discoverability-maintainers
|
||||
/docs/features/search @backstage/discoverability-maintainers
|
||||
/docs/features/techdocs @backstage/techdocs-maintainers
|
||||
|
||||
+3
-3
@@ -144,15 +144,15 @@ site
|
||||
# Sensitive credentials
|
||||
*-credentials.yaml
|
||||
|
||||
# e2e tests
|
||||
cypress/cypress/*
|
||||
|
||||
# Possible leftover from build:api-reports
|
||||
tsconfig.tmp.json
|
||||
|
||||
# vscode database functionality support files
|
||||
*.session.sql
|
||||
|
||||
# E2E test reports
|
||||
e2e-test-report/
|
||||
|
||||
# Lighthouse CI Reports
|
||||
**/.lighthouseci/*
|
||||
!**/.lighthouseci/scripts
|
||||
|
||||
@@ -291,9 +291,6 @@ catalog:
|
||||
target: ../../plugins/scaffolder-backend/sample-templates/all-templates.yaml
|
||||
rules:
|
||||
- allow: [Template]
|
||||
# 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:
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
module.exports = {
|
||||
extends: [require.resolve('@backstage/cli/config/eslint.backend')],
|
||||
rules: {
|
||||
'no-console': 0,
|
||||
'jest/valid-expect': 'off',
|
||||
'jest/expect-expect': 'off',
|
||||
'no-restricted-syntax': 'off',
|
||||
},
|
||||
};
|
||||
@@ -1,2 +0,0 @@
|
||||
registry=https://registry.npmjs.org/
|
||||
engine-strict=true
|
||||
@@ -1,5 +0,0 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
registry "https://registry.npmjs.org/"
|
||||
network-timeout 300000
|
||||
@@ -1,34 +0,0 @@
|
||||
# Cypress Tests for Backstage
|
||||
|
||||
Hey 👋 Welcome to the Cypress tests for Backstage. They're designed to be run against the `packages/app` folder in the main repo, and be some form of smoke tests to make sure that we don't break any core functionality.
|
||||
|
||||
### Running Locally
|
||||
|
||||
In order to make typescript happy, this `cypress` package is separate from all the Jest dependencies in the monorepo workspaces setup.
|
||||
|
||||
You can run the e2e tests locally pointing at your local running version like so:
|
||||
|
||||
```sh
|
||||
cd cypress
|
||||
yarn install
|
||||
yarn cypress run
|
||||
```
|
||||
|
||||
Note that the tests expect to run against a built application, so you'll want to
|
||||
run a Docker image and either create an `app-config.cypress.yaml` or pass the
|
||||
necessary environment variables:
|
||||
|
||||
```sh
|
||||
yarn tsc
|
||||
yarn build:backend
|
||||
yarn workspace example-backend build-image
|
||||
docker run -p 7007:7007 example-backend
|
||||
```
|
||||
|
||||
You can open up the `cypress` console by using `yarn cypress open`.
|
||||
|
||||
You can also run towards any Backstage installation by using the Cypress Environment Variable overrides.
|
||||
|
||||
```sh
|
||||
CYPRESS_baseUrl="http://demo.backstage.io" yarn cypress run
|
||||
```
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:7007",
|
||||
"integrationFolder": "./src/integration",
|
||||
"supportFile": "./src/support",
|
||||
"fixturesFolder": "./src/fixtures",
|
||||
"pluginsFile": "./src/plugins",
|
||||
"defaultCommandTimeout": 10000,
|
||||
"viewportHeight": 900,
|
||||
"viewportWidth": 1440
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
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
|
||||
@@ -1,3 +0,0 @@
|
||||
# Home page
|
||||
|
||||
This is a basic documentation used for end-to-end tests.
|
||||
@@ -1,109 +0,0 @@
|
||||
# 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!
|
||||
@@ -1,121 +0,0 @@
|
||||
# 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!
|
||||
@@ -1,146 +0,0 @@
|
||||
# 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)
|
||||
@@ -1,13 +0,0 @@
|
||||
site_name: e2e Fixture Documentation
|
||||
site_description: Documentation used for end-to-end tests of TechDocs in Backstage.
|
||||
repo_url: https://github.com/backstage/backstage
|
||||
edit_uri: edit/master/cypress/fixtures/docs
|
||||
|
||||
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
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"name": "@backstage/cypress-tests",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"cypress": "^12.0.0",
|
||||
"typescript": "~5.0.0"
|
||||
}
|
||||
}
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/// <reference types="cypress" />
|
||||
import 'os';
|
||||
|
||||
describe('Integrations', () => {
|
||||
describe('ReadTree', () => {
|
||||
it('should work for github', () => {
|
||||
cy.loginAsGuest();
|
||||
|
||||
cy.request('POST', '/api/catalog/locations', {
|
||||
target:
|
||||
'https://github.com/backstage-verification/test-repo/blob/main/**/*',
|
||||
type: 'url',
|
||||
});
|
||||
|
||||
cy.wait(5000);
|
||||
|
||||
cy.visit('/catalog');
|
||||
cy.get('[data-testid="user-picker-all"]').click();
|
||||
cy.get('table').should('contain', 'github-repo');
|
||||
cy.get('table').should('contain', 'github-repo-nested');
|
||||
});
|
||||
|
||||
// it('should work for azure', () => {
|
||||
// cy.loginAsGuest();
|
||||
|
||||
// cy.request('POST', '/api/catalog/locations', {
|
||||
// target:
|
||||
// 'https://dev.azure.com/backstage-verification/_git/test-repo?path=*',
|
||||
// type: 'url',
|
||||
// });
|
||||
// });
|
||||
|
||||
it('should work for gitlab', () => {
|
||||
cy.loginAsGuest();
|
||||
|
||||
cy.request('POST', '/api/catalog/locations', {
|
||||
target:
|
||||
'https://gitlab.com/backstage-verification/test-repo/-/tree/master/**/*',
|
||||
type: 'url',
|
||||
});
|
||||
|
||||
cy.wait(5000);
|
||||
|
||||
cy.visit('/catalog');
|
||||
cy.get('[data-testid="user-picker-all"]').click();
|
||||
cy.get('table').should('contain', 'gitlab-repo');
|
||||
cy.get('table').should('contain', 'gitlab-repo-nested');
|
||||
});
|
||||
|
||||
it('should work for bitbucket', () => {
|
||||
cy.loginAsGuest();
|
||||
|
||||
cy.request('POST', '/api/catalog/locations', {
|
||||
target:
|
||||
'https://bitbucket.org/backstage-verification/test-repo/src/master/**/*',
|
||||
type: 'url',
|
||||
});
|
||||
|
||||
cy.wait(5000);
|
||||
|
||||
cy.visit('/catalog');
|
||||
cy.get('[data-testid="user-picker-all"]').click();
|
||||
cy.get('table').should('contain', 'bitbucket-repo');
|
||||
cy.get('table').should('contain', 'bitbucket-repo-nested');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/// <reference types="cypress" />
|
||||
import 'os';
|
||||
|
||||
describe('Catalog', () => {
|
||||
describe('default entities', () => {
|
||||
it('displays the correct amount of entities from default config', () => {
|
||||
cy.loginAsGuest();
|
||||
|
||||
cy.visit('/catalog');
|
||||
|
||||
cy.contains('Owned (10)').should('be.visible');
|
||||
});
|
||||
|
||||
it('Should navigate to a docs tab', () => {
|
||||
cy.loginAsGuest();
|
||||
|
||||
cy.visit('/catalog');
|
||||
|
||||
cy.contains('techdocs-e2e-fixture').click();
|
||||
|
||||
cy.location().should(loc => {
|
||||
expect(loc.pathname).to.eq(
|
||||
'/catalog/default/component/techdocs-e2e-fixture',
|
||||
);
|
||||
});
|
||||
|
||||
cy.getCatalogDocsTab().click();
|
||||
|
||||
cy.getTechDocsShadowRoot()
|
||||
.find('h1')
|
||||
.contains('Home page')
|
||||
.should('be.visible');
|
||||
});
|
||||
|
||||
it('Should navigate to a sub-route in docs tab', () => {
|
||||
cy.loginAsGuest();
|
||||
|
||||
cy.visit('/catalog');
|
||||
|
||||
cy.contains('techdocs-e2e-fixture').click();
|
||||
|
||||
cy.location().should(loc => {
|
||||
expect(loc.pathname).to.eq(
|
||||
'/catalog/default/component/techdocs-e2e-fixture',
|
||||
);
|
||||
});
|
||||
|
||||
cy.getCatalogDocsTab().click();
|
||||
|
||||
cy.getTechDocsShadowRoot()
|
||||
.find('h1')
|
||||
.contains('Home page')
|
||||
.should('be.visible');
|
||||
|
||||
cy.getTechDocsShadowRoot().within(() => {
|
||||
cy.getTechDocsNavigation().find('a').contains('Sub-page 1').click();
|
||||
});
|
||||
|
||||
cy.location().should(loc => {
|
||||
expect(loc.pathname).to.eq(
|
||||
'/catalog/default/component/techdocs-e2e-fixture/docs/sub-page-one/',
|
||||
);
|
||||
});
|
||||
|
||||
cy.getTechDocsShadowRoot()
|
||||
.find('h1')
|
||||
.contains('Sub-page 1')
|
||||
.should('be.visible');
|
||||
});
|
||||
|
||||
it('Should render addons on docs tab homepage', () => {
|
||||
cy.loginAsGuest();
|
||||
|
||||
cy.visit('/catalog');
|
||||
|
||||
cy.contains('techdocs-e2e-fixture').click();
|
||||
|
||||
cy.location().should(loc => {
|
||||
expect(loc.pathname).to.eq(
|
||||
'/catalog/default/component/techdocs-e2e-fixture',
|
||||
);
|
||||
});
|
||||
|
||||
cy.getCatalogDocsTab().click();
|
||||
|
||||
cy.wait(300);
|
||||
|
||||
cy.getTechDocsShadowRoot()
|
||||
.find('h1')
|
||||
.contains('Home page')
|
||||
.should('be.visible');
|
||||
|
||||
// highlight a snippet of text
|
||||
cy.getTechDocsShadowRoot()
|
||||
.find('article > p')
|
||||
.then($el => {
|
||||
const el = $el[0];
|
||||
const document = el.ownerDocument;
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(el);
|
||||
document?.getSelection()?.removeAllRanges();
|
||||
document?.getSelection()?.addRange(range);
|
||||
});
|
||||
|
||||
cy.document().trigger('selectionchange');
|
||||
|
||||
// wait for new issue default debounce time
|
||||
cy.wait(600);
|
||||
|
||||
// assert that the new issue button has a right url
|
||||
cy.getTechDocsShadowRoot()
|
||||
.contains('Open new Github issue')
|
||||
.should(
|
||||
'have.attr',
|
||||
'href',
|
||||
'https://github.com/backstage/backstage/issues/new?title=Documentation%20feedback%3A%20This%20is%20a%20basic%20documentation%20used%20for%20end-to-end%20tests.&body=%23%23%20Documentation%20Feedback%20%F0%9F%93%9D%0A%0A%20%23%23%23%23%20The%20highlighted%20text%3A%20%0A%0A%20%3E%20This%20is%20a%20basic%20documentation%20used%20for%20end-to-end%20tests.%0A%0A%20%23%23%23%23%20The%20comment%20on%20the%20text%3A%20%0A%20_%3Ereplace%20this%20line%20with%20your%20comment%3C_%0A%0A%20___%0ABackstage%20URL%3A%20%3Chttp%3A%2F%2Flocalhost%3A7007%2Fcatalog%2Fdefault%2Fcomponent%2Ftechdocs-e2e-fixture%2Fdocs%3E%20%0AMarkdown%20URL%3A%20%3Chttps%3A%2F%2Fgithub.com%2Fbackstage%2Fbackstage%2Fblob%2Fmaster%2Fcypress%2Ffixtures%2Fdocs%2Findex.md%3E',
|
||||
);
|
||||
});
|
||||
|
||||
it('Should render addons on docs tab sup-page', () => {
|
||||
cy.loginAsGuest();
|
||||
|
||||
cy.visit('/catalog');
|
||||
|
||||
cy.contains('techdocs-e2e-fixture').click();
|
||||
|
||||
cy.location().should(loc => {
|
||||
expect(loc.pathname).to.eq(
|
||||
'/catalog/default/component/techdocs-e2e-fixture',
|
||||
);
|
||||
});
|
||||
|
||||
cy.getCatalogDocsTab().click();
|
||||
|
||||
cy.wait(300);
|
||||
|
||||
cy.getTechDocsShadowRoot()
|
||||
.find('h1')
|
||||
.contains('Home page')
|
||||
.should('be.visible');
|
||||
|
||||
cy.getTechDocsShadowRoot().within(() => {
|
||||
cy.getTechDocsNavigation().find('a').contains('Sub-page 1').click();
|
||||
});
|
||||
|
||||
cy.location().should(loc => {
|
||||
expect(loc.pathname).to.eq(
|
||||
'/catalog/default/component/techdocs-e2e-fixture/docs/sub-page-one/',
|
||||
);
|
||||
});
|
||||
|
||||
cy.getTechDocsShadowRoot()
|
||||
.find('h1')
|
||||
.contains('Sub-page 1')
|
||||
.should('be.visible');
|
||||
|
||||
// highlight a snippet of text
|
||||
cy.getTechDocsShadowRoot()
|
||||
.find('#section-11')
|
||||
.then($el => {
|
||||
const el = $el[0];
|
||||
const document = el.ownerDocument;
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(el);
|
||||
document?.getSelection()?.removeAllRanges();
|
||||
document?.getSelection()?.addRange(range);
|
||||
});
|
||||
|
||||
cy.document().trigger('selectionchange');
|
||||
|
||||
// wait for new issue default debounce time
|
||||
cy.wait(600);
|
||||
|
||||
// assert that the new issue button has a right url
|
||||
cy.getTechDocsShadowRoot()
|
||||
.contains('Open new Github issue')
|
||||
.should(
|
||||
'have.attr',
|
||||
'href',
|
||||
'https://github.com/backstage/backstage/issues/new?title=Documentation%20feedback%3A%20Section%201.1%C2%B6&body=%23%23%20Documentation%20Feedback%20%F0%9F%93%9D%0A%0A%20%23%23%23%23%20The%20highlighted%20text%3A%20%0A%0A%20%3E%20Section%201.1%C2%B6%0A%0A%20%23%23%23%23%20The%20comment%20on%20the%20text%3A%20%0A%20_%3Ereplace%20this%20line%20with%20your%20comment%3C_%0A%0A%20___%0ABackstage%20URL%3A%20%3Chttp%3A%2F%2Flocalhost%3A7007%2Fcatalog%2Fdefault%2Fcomponent%2Ftechdocs-e2e-fixture%2Fdocs%2Fsub-page-one%2F%3E%20%0AMarkdown%20URL%3A%20%3Chttps%3A%2F%2Fgithub.com%2Fbackstage%2Fbackstage%2Fblob%2Fmaster%2Fcypress%2Ffixtures%2Fdocs%2Fsub-page-one.md%3E',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,83 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/// <reference types="cypress" />
|
||||
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 <P/> 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',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,259 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
/// <reference types="cypress" />
|
||||
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').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',
|
||||
);
|
||||
|
||||
// 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('Rendering TechDocs Addons', () => {
|
||||
it('should render a content addon in homepage', () => {
|
||||
cy.visit('/docs/default/Component/techdocs-e2e-fixture');
|
||||
|
||||
cy.contains('e2e Fixture Documentation');
|
||||
|
||||
// highlight a snippet of text
|
||||
cy.getTechDocsShadowRoot()
|
||||
.find('article > p')
|
||||
.then($el => {
|
||||
const el = $el[0];
|
||||
const document = el.ownerDocument;
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(el);
|
||||
document?.getSelection()?.removeAllRanges();
|
||||
document?.getSelection()?.addRange(range);
|
||||
});
|
||||
|
||||
cy.document().trigger('selectionchange');
|
||||
|
||||
// wait for new issue default debounce time
|
||||
cy.wait(600);
|
||||
|
||||
// assert that the new issue button has a right url
|
||||
cy.getTechDocsShadowRoot()
|
||||
.contains('Open new Github issue')
|
||||
.should(
|
||||
'have.attr',
|
||||
'href',
|
||||
'https://github.com/backstage/backstage/issues/new?title=Documentation%20feedback%3A%20This%20is%20a%20basic%20documentation%20used%20for%20end-to-end%20tests.&body=%23%23%20Documentation%20Feedback%20%F0%9F%93%9D%0A%0A%20%23%23%23%23%20The%20highlighted%20text%3A%20%0A%0A%20%3E%20This%20is%20a%20basic%20documentation%20used%20for%20end-to-end%20tests.%0A%0A%20%23%23%23%23%20The%20comment%20on%20the%20text%3A%20%0A%20_%3Ereplace%20this%20line%20with%20your%20comment%3C_%0A%0A%20___%0ABackstage%20URL%3A%20%3Chttp%3A%2F%2Flocalhost%3A7007%2Fdocs%2Fdefault%2FComponent%2Ftechdocs-e2e-fixture%3E%20%0AMarkdown%20URL%3A%20%3Chttps%3A%2F%2Fgithub.com%2Fbackstage%2Fbackstage%2Fblob%2Fmaster%2Fcypress%2Ffixtures%2Fdocs%2Findex.md%3E',
|
||||
);
|
||||
});
|
||||
|
||||
it('should render a content addon in sub-pages', () => {
|
||||
cy.visit('/docs/default/Component/techdocs-e2e-fixture');
|
||||
|
||||
cy.contains('e2e Fixture Documentation');
|
||||
|
||||
// open sub-page
|
||||
cy.getTechDocsShadowRoot().within(() => {
|
||||
cy.getTechDocsNavigation().find('a').contains('Sub-page 1').click();
|
||||
});
|
||||
|
||||
// highlight a snippet of text
|
||||
cy.getTechDocsShadowRoot()
|
||||
.find('#section-11')
|
||||
.then($el => {
|
||||
const el = $el[0];
|
||||
const document = el.ownerDocument;
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(el);
|
||||
document?.getSelection()?.removeAllRanges();
|
||||
document?.getSelection()?.addRange(range);
|
||||
});
|
||||
|
||||
cy.document().trigger('selectionchange');
|
||||
|
||||
// wait for new issue default debounce time
|
||||
cy.wait(600);
|
||||
|
||||
// assert that the new issue button has a right url
|
||||
cy.getTechDocsShadowRoot()
|
||||
.contains('Open new Github issue')
|
||||
.should(
|
||||
'have.attr',
|
||||
'href',
|
||||
'https://github.com/backstage/backstage/issues/new?title=Documentation%20feedback%3A%20Section%201.1%C2%B6&body=%23%23%20Documentation%20Feedback%20%F0%9F%93%9D%0A%0A%20%23%23%23%23%20The%20highlighted%20text%3A%20%0A%0A%20%3E%20Section%201.1%C2%B6%0A%0A%20%23%23%23%23%20The%20comment%20on%20the%20text%3A%20%0A%20_%3Ereplace%20this%20line%20with%20your%20comment%3C_%0A%0A%20___%0ABackstage%20URL%3A%20%3Chttp%3A%2F%2Flocalhost%3A7007%2Fdocs%2Fdefault%2FComponent%2Ftechdocs-e2e-fixture%2Fsub-page-one%2F%3E%20%0AMarkdown%20URL%3A%20%3Chttps%3A%2F%2Fgithub.com%2Fbackstage%2Fbackstage%2Fblob%2Fmaster%2Fcypress%2Ffixtures%2Fdocs%2Fsub-page-one.md%3E',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
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.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');
|
||||
});
|
||||
|
||||
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()
|
||||
.find('a')
|
||||
.contains('Section 2.3')
|
||||
.click();
|
||||
|
||||
// wait scroll timeout
|
||||
cy.wait(500);
|
||||
|
||||
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('a')
|
||||
.contains('Section 2.2.2')
|
||||
.click();
|
||||
|
||||
// wait scroll timeout
|
||||
cy.wait(500);
|
||||
|
||||
cy.isInViewport('#sub-section-222');
|
||||
});
|
||||
});
|
||||
|
||||
it('should navigate to a specific TechDocs page fragment from a link', () => {
|
||||
return cy.getTechDocsShadowRoot().within(() => {
|
||||
cy.get('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('footer a').contains('Sub-page 3').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('footer a').contains('Sub-page 1').click();
|
||||
|
||||
cy.location().should(loc => {
|
||||
expect(loc.pathname).to.eq(
|
||||
'/docs/default/Component/techdocs-e2e-fixture/sub-page-one/',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
/// <reference types="cypress" />
|
||||
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;
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,125 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
/* eslint-disable jest/no-standalone-expect */
|
||||
/// <reference types="cypress" />
|
||||
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-native-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-type="toc"]');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('getTechDocsNavigation', () => {
|
||||
cy.get('[data-md-type="navigation"]');
|
||||
});
|
||||
|
||||
Cypress.Commands.add('getCatalogDocsTab', () => {
|
||||
cy.get('button[role="tab"]').contains('Docs');
|
||||
});
|
||||
|
||||
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']);
|
||||
});
|
||||
|
||||
Cypress.Commands.add('checkForErrors', () => {
|
||||
// when an error occurs there is a <div> 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');
|
||||
});
|
||||
Vendored
-86
@@ -1,86 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
declare module 'zombie';
|
||||
declare module 'pgtools';
|
||||
declare namespace Cypress {
|
||||
interface Chainable {
|
||||
/**
|
||||
* Login as guest
|
||||
* @example cy.loginAsGuests
|
||||
*/
|
||||
loginAsGuest(): Chainable<Element>;
|
||||
/**
|
||||
* Get the TechDocs shadow root element
|
||||
* @example cy.getTechDocsShadowRoot
|
||||
*/
|
||||
getTechDocsShadowRoot(): Chainable<Element>;
|
||||
/**
|
||||
* Mock TechDocs backend API
|
||||
* @example cy.mockTechDocs
|
||||
*/
|
||||
mockTechDocs(): void;
|
||||
/**
|
||||
* Get the TechDocs table of contents element
|
||||
* @example cy.getTechDocsShadowRoot
|
||||
*/
|
||||
getTechDocsTableOfContents(): Chainable<Element>;
|
||||
/**
|
||||
* Get the TechDocs navigation element
|
||||
* @example cy.getTechDocsNavigation
|
||||
*/
|
||||
getTechDocsNavigation(): Chainable<Element>;
|
||||
/**
|
||||
* Get the Catalog docs tab
|
||||
* @example cy.getCatalogDocsTab
|
||||
*/
|
||||
getCatalogDocsTab(): Chainable<Element>;
|
||||
/**
|
||||
* Intercept the TechDocs API calls
|
||||
* @example cy.interceptTechDocsAPICalls
|
||||
*/
|
||||
interceptTechDocsAPICalls(): Chainable<Element>;
|
||||
/**
|
||||
* Mock SockJS-Node call
|
||||
* @example cy.mockSockJSNode
|
||||
*/
|
||||
mockSockJSNode(): Chainable<Element>;
|
||||
/**
|
||||
* Wait TechDocs API response for home page
|
||||
* @example cy.waitHomePage
|
||||
*/
|
||||
waitHomePage(): Chainable<Element>;
|
||||
/**
|
||||
* Wait TechDocs API response for Section 2 page
|
||||
* @example cy.waitSectionTwoPage
|
||||
*/
|
||||
waitSectionTwoPage(): Chainable<Element>;
|
||||
/**
|
||||
* Check if the element is in viewport
|
||||
* @example cy.isInViewport
|
||||
*/
|
||||
isInViewport(element: string): Chainable<Element>;
|
||||
/**
|
||||
* Check if the element is not in viewport
|
||||
* @example cy.isNotInViewport
|
||||
*/
|
||||
isNotInViewport(element: string): Chainable<Element>;
|
||||
/**
|
||||
* Check if we have not caused error by our last action
|
||||
* @example cy.checkForErrors
|
||||
*/
|
||||
checkForErrors(): Chainable<Element>;
|
||||
}
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
// ***********************************************
|
||||
// This example commands.ts shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
//
|
||||
// declare global {
|
||||
// namespace Cypress {
|
||||
// interface Chainable {
|
||||
// login(email: string, password: string): Chainable<void>
|
||||
// drag(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||
// dismiss(subject: string, options?: Partial<TypeOptions>): Chainable<Element>
|
||||
// visit(originalFn: CommandOriginalFn, url: string, options: Partial<VisitOptions>): Chainable<Element>
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
// This example support/e2e.ts is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands';
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
@@ -1,37 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"declaration": true,
|
||||
"declarationMap": false,
|
||||
"esModuleInterop": true,
|
||||
"experimentalDecorators": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"importHelpers": false,
|
||||
"incremental": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "react",
|
||||
"lib": ["DOM", "DOM.Iterable", "ScriptHost", "ES2021", "ESNext.Promise"],
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"noEmit": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"pretty": true,
|
||||
"removeComments": false,
|
||||
"resolveJsonModule": true,
|
||||
"sourceMap": false,
|
||||
"skipLibCheck": false,
|
||||
"strict": true,
|
||||
"strictBindCallApply": true,
|
||||
"strictFunctionTypes": true,
|
||||
"strictNullChecks": true,
|
||||
"strictPropertyInitialization": true,
|
||||
"stripInternal": true,
|
||||
"target": "ES2021",
|
||||
"types": ["node", "cypress"]
|
||||
}
|
||||
}
|
||||
-1639
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,7 @@
|
||||
"clean": "backstage-cli repo clean",
|
||||
"test": "backstage-cli repo test",
|
||||
"test:all": "backstage-cli repo test --coverage",
|
||||
"test:e2e": "playwright test",
|
||||
"fix": "backstage-cli repo fix",
|
||||
"lint": "backstage-cli repo lint --since origin/master",
|
||||
"lint:docs": "node ./scripts/check-docs-quality",
|
||||
@@ -58,9 +59,11 @@
|
||||
"@backstage/cli": "workspace:*",
|
||||
"@backstage/codemods": "workspace:*",
|
||||
"@backstage/create-app": "workspace:*",
|
||||
"@backstage/e2e-test-utils": "workspace:*",
|
||||
"@backstage/repo-tools": "workspace:*",
|
||||
"@changesets/cli": "^2.14.0",
|
||||
"@octokit/rest": "^19.0.3",
|
||||
"@playwright/test": "^1.32.3",
|
||||
"@spotify/eslint-plugin": "^14.1.3",
|
||||
"@spotify/prettier-config": "^14.0.0",
|
||||
"@techdocs/cli": "workspace:*",
|
||||
|
||||
@@ -99,7 +99,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/test-utils": "workspace:^",
|
||||
"@testing-library/cypress": "^9.0.0",
|
||||
"@testing-library/dom": "^8.0.0",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^12.1.3",
|
||||
@@ -108,21 +107,14 @@
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"@types/zen-observable": "^0.8.0",
|
||||
"cross-env": "^7.0.0",
|
||||
"cypress": "^12.0.0",
|
||||
"eslint-plugin-cypress": "^2.10.3",
|
||||
"start-server-and-test": "^1.10.11"
|
||||
"cross-env": "^7.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "backstage-cli package start --config ../../app-config.yaml --config app-config.yaml",
|
||||
"build": "backstage-cli package build",
|
||||
"clean": "backstage-cli package clean",
|
||||
"test": "backstage-cli package test",
|
||||
"lint": "backstage-cli package lint",
|
||||
"test:e2e": "start-server-and-test start http://localhost:3000 cy:dev",
|
||||
"test:e2e:ci": "start-server-and-test start http://localhost:3000 cy:run",
|
||||
"cy:dev": "cypress open",
|
||||
"cy:run": "cypress run"
|
||||
"lint": "backstage-cli package lint"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:3000",
|
||||
"fixturesFolder": false,
|
||||
"pluginsFile": false
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"plugins": ["cypress"],
|
||||
"extends": ["plugin:cypress/recommended"],
|
||||
"rules": {
|
||||
"jest/expect-expect": [
|
||||
"error",
|
||||
{
|
||||
"assertFunctionNames": ["expect", "cy.contains", "cy.**.should"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 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.
|
||||
*/
|
||||
|
||||
describe('App', () => {
|
||||
it('should render the welcome page', () => {
|
||||
cy.visit('/');
|
||||
cy.contains('Welcome to Backstage');
|
||||
cy.contains('Getting Started');
|
||||
cy.contains('Quick Links');
|
||||
cy.contains('APIs');
|
||||
});
|
||||
|
||||
it('should display support info when clicking the button', () => {
|
||||
cy.visit('/');
|
||||
// eslint-disable-next-line testing-library/await-async-query
|
||||
cy.findByTestId('support-button').click({ force: true });
|
||||
cy.contains('#backstage');
|
||||
});
|
||||
|
||||
it('should display error message when triggering it', () => {
|
||||
cy.visit('/');
|
||||
// eslint-disable-next-line testing-library/await-async-query
|
||||
cy.findByTestId('error-button').click({ force: true });
|
||||
cy.contains('Error: Oh no!');
|
||||
// eslint-disable-next-line testing-library/await-async-query
|
||||
cy.findByTestId('error-button-close').click({ force: true });
|
||||
});
|
||||
|
||||
it('should be able to login and logout', () => {
|
||||
const name = 'test-name';
|
||||
Cypress.on('window:before:load', win => {
|
||||
win.fetch = cy.stub().resolves({
|
||||
status: 200,
|
||||
json: () => ({ username: 'test name', token: 'token', name }),
|
||||
});
|
||||
});
|
||||
|
||||
cy.visit('/');
|
||||
cy.get('a[href="/login"]').click({ force: true });
|
||||
cy.url().should('include', '/login');
|
||||
cy.contains('Welcome, guest!');
|
||||
cy.contains('Username')
|
||||
.get('input[name=github-username-tf]')
|
||||
.type(name, { force: true });
|
||||
cy.contains('Token')
|
||||
.get('input[name=github-auth-tf]')
|
||||
.type('password', { force: true });
|
||||
// eslint-disable-next-line testing-library/await-async-query
|
||||
cy.findByTestId('github-auth-button').click({ force: true });
|
||||
cy.contains(`Welcome, ${name}!`);
|
||||
cy.contains('Logout').click({ force: true });
|
||||
cy.contains('Welcome, guest!');
|
||||
});
|
||||
});
|
||||
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
const API_ENDPOINT = 'http://localhost:7007/api/search/query';
|
||||
|
||||
describe('SearchPage', () => {
|
||||
describe('Given a search context with a term, results, and filter values', () => {
|
||||
it('The results are rendered as expected', () => {
|
||||
const results = [
|
||||
{
|
||||
type: 'software-catalog',
|
||||
document: {
|
||||
title: 'backstage',
|
||||
text: 'Backstage system documentation',
|
||||
location: '/result/location/path',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
cy.enterAsGuest();
|
||||
cy.visit('/search-next', {
|
||||
onBeforeLoad(win) {
|
||||
cy.stub(win, 'fetch')
|
||||
.withArgs(`${API_ENDPOINT}?term=`)
|
||||
.resolves({
|
||||
ok: true,
|
||||
json: () => ({ results }),
|
||||
});
|
||||
},
|
||||
});
|
||||
cy.contains('Search');
|
||||
|
||||
cy.contains(results[0].document.title);
|
||||
cy.contains(results[0].document.text);
|
||||
cy.get(`a[href="${results[0].document.location}"]`).should('be.visible');
|
||||
});
|
||||
|
||||
it('The filters are rendered as expected', () => {
|
||||
cy.enterAsGuest();
|
||||
cy.visit(
|
||||
'/search-next?filters%5Bkind%5D=Component&filters%5Blifecycle%5D%5B%5D=experimental',
|
||||
{
|
||||
onBeforeLoad(win) {
|
||||
cy.stub(win, 'fetch')
|
||||
.withArgs(
|
||||
`${API_ENDPOINT}?term=&filters%5Bkind%5D=Component&filters%5Blifecycle%5D%5B0%5D=experimental`,
|
||||
)
|
||||
.resolves({
|
||||
ok: true,
|
||||
json: () => ({ results: [] }),
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
cy.contains('Search');
|
||||
|
||||
// lifecycle
|
||||
cy.contains('lifecycle');
|
||||
|
||||
cy.contains('experimental');
|
||||
cy.get(
|
||||
'[data-testid="search-checkboxfilter-next"] input[value="experimental"]',
|
||||
).should('have.attr', 'checked');
|
||||
|
||||
cy.contains('production');
|
||||
cy.get(
|
||||
'[data-testid="search-checkboxfilter-next"] input[value="production"]',
|
||||
).should('not.have.attr', 'checked');
|
||||
|
||||
// kind
|
||||
cy.contains('kind');
|
||||
cy.get(
|
||||
'[data-testid="search-selectfilter-next"] [role="button"][aria-haspopup="listbox"]',
|
||||
).click();
|
||||
|
||||
cy.contains('All');
|
||||
cy.contains('Template');
|
||||
cy.contains('Component');
|
||||
|
||||
cy.get('[role="option"][data-value="Component"]').should(
|
||||
'have.attr',
|
||||
'aria-selected',
|
||||
'true',
|
||||
);
|
||||
});
|
||||
|
||||
it('The search bar is rendered as expected', () => {
|
||||
cy.enterAsGuest();
|
||||
cy.visit('/search-next?query=backstage', {
|
||||
onBeforeLoad(win) {
|
||||
cy.stub(win, 'fetch')
|
||||
.withArgs(`${API_ENDPOINT}?term=backstage`)
|
||||
.resolves({
|
||||
ok: true,
|
||||
json: () => ({ results: [] }),
|
||||
});
|
||||
},
|
||||
});
|
||||
cy.contains('Search');
|
||||
|
||||
cy.get('[data-testid="search-bar-next"] input').should(
|
||||
'have.attr',
|
||||
'value',
|
||||
'backstage',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 { test, expect } from '@playwright/test';
|
||||
|
||||
test('the results are rendered as expected', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const enterButton = page.getByRole('button', { name: 'Enter' });
|
||||
await expect(enterButton).toBeVisible();
|
||||
await enterButton.click();
|
||||
|
||||
await page.goto('/search');
|
||||
await page.route(`http://*/api/search/query?term=*`, async route => {
|
||||
const results = [
|
||||
{
|
||||
type: 'software-catalog',
|
||||
document: {
|
||||
title: 'backstage',
|
||||
text: 'Backstage system documentation',
|
||||
location: '/result/location/path',
|
||||
},
|
||||
},
|
||||
];
|
||||
await route.fulfill({ json: { results } });
|
||||
});
|
||||
|
||||
await expect(
|
||||
page.getByPlaceholder('Search in Backstage Example App'),
|
||||
).toBeVisible();
|
||||
|
||||
await expect(page.getByText('Backstage system documentation')).toBeVisible();
|
||||
});
|
||||
@@ -13,19 +13,21 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/// <reference types="cypress" />
|
||||
import 'os';
|
||||
|
||||
describe('Login', () => {
|
||||
it('should render the login page', () => {
|
||||
cy.visit('/');
|
||||
cy.contains('Select a sign-in method');
|
||||
});
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
it('should be able to login', () => {
|
||||
cy.get('button').contains('Enter').click();
|
||||
cy.url().should('include', '/catalog');
|
||||
test('App should render the welcome page', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
cy.contains('artist-lookup');
|
||||
});
|
||||
const enterButton = page.getByRole('button', { name: 'Enter' });
|
||||
await expect(enterButton).toBeVisible();
|
||||
await enterButton.click();
|
||||
|
||||
await expect(page.getByText('My Company Catalog')).toBeVisible();
|
||||
|
||||
const supportButton = page.getByTestId('support-button');
|
||||
await expect(supportButton).toBeVisible();
|
||||
await supportButton.click();
|
||||
|
||||
await expect(page.getByText('#backstage')).toBeVisible();
|
||||
});
|
||||
@@ -103,7 +103,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/test-utils": "workspace:^",
|
||||
"@testing-library/cypress": "^9.0.0",
|
||||
"@playwright/test": "^1.32.3",
|
||||
"@testing-library/dom": "^8.0.0",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^12.1.3",
|
||||
@@ -112,21 +112,14 @@
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"@types/zen-observable": "^0.8.0",
|
||||
"cross-env": "^7.0.0",
|
||||
"cypress": "^12.0.0",
|
||||
"eslint-plugin-cypress": "^2.10.3",
|
||||
"start-server-and-test": "^1.10.11"
|
||||
"cross-env": "^7.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "backstage-cli package start",
|
||||
"build": "backstage-cli package build",
|
||||
"clean": "backstage-cli package clean",
|
||||
"test": "backstage-cli package test",
|
||||
"lint": "backstage-cli package lint",
|
||||
"test:e2e": "start-server-and-test start http://localhost:3000 cy:dev",
|
||||
"test:e2e:ci": "start-server-and-test start http://localhost:3000 cy:run",
|
||||
"cy:dev": "cypress open",
|
||||
"cy:run": "cypress run"
|
||||
"lint": "backstage-cli package lint"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
||||
@@ -66,6 +66,7 @@ jest.mock('./versions', () => ({
|
||||
'@backstage/core-app-api': '1.0.0',
|
||||
'@backstage/core-components': '1.0.0',
|
||||
'@backstage/core-plugin-api': '1.0.0',
|
||||
'@backstage/e2e-test-utils': '1.0.0',
|
||||
'@backstage/integration-react': '1.0.0',
|
||||
'@backstage/plugin-api-docs': '1.0.0',
|
||||
'@backstage/plugin-catalog': '1.0.0',
|
||||
|
||||
@@ -41,6 +41,7 @@ import { version as config } from '../../../config/package.json';
|
||||
import { version as coreAppApi } from '../../../core-app-api/package.json';
|
||||
import { version as coreComponents } from '../../../core-components/package.json';
|
||||
import { version as corePluginApi } from '../../../core-plugin-api/package.json';
|
||||
import { version as e2eTestUtils } from '../../../e2e-test-utils/package.json';
|
||||
import { version as errors } from '../../../errors/package.json';
|
||||
import { version as integrationReact } from '../../../integration-react/package.json';
|
||||
import { version as testUtils } from '../../../test-utils/package.json';
|
||||
@@ -92,6 +93,7 @@ export const packageVersions = {
|
||||
'@backstage/core-app-api': coreAppApi,
|
||||
'@backstage/core-components': coreComponents,
|
||||
'@backstage/core-plugin-api': corePluginApi,
|
||||
'@backstage/e2e-test-utils': e2eTestUtils,
|
||||
'@backstage/errors': errors,
|
||||
'@backstage/integration-react': integrationReact,
|
||||
'@backstage/plugin-api-docs': pluginApiDocs,
|
||||
|
||||
@@ -49,3 +49,6 @@ site
|
||||
|
||||
# vscode database functionality support files
|
||||
*.session.sql
|
||||
|
||||
# E2E test reports
|
||||
e2e-test-report/
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
"clean": "backstage-cli repo clean",
|
||||
"test": "backstage-cli repo test",
|
||||
"test:all": "backstage-cli repo test --coverage",
|
||||
"test:e2e": "playwright test",
|
||||
"fix": "backstage-cli repo fix",
|
||||
"lint": "backstage-cli repo lint --since origin/{{defaultBranch}}",
|
||||
"lint:all": "backstage-cli repo lint",
|
||||
@@ -31,6 +32,8 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "^{{version '@backstage/cli'}}",
|
||||
"@backstage/e2e-test-utils": "^{{version '@backstage/e2e-test-utils'}}",
|
||||
"@playwright/test": "^1.32.3",
|
||||
"@spotify/prettier-config": "^12.0.0",
|
||||
"concurrently": "^8.0.0",
|
||||
"lerna": "^4.0.0",
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
const { defineConfig } = require('cypress');
|
||||
|
||||
module.exports = defineConfig({
|
||||
fixturesFolder: false,
|
||||
retries: 3,
|
||||
|
||||
e2e: {
|
||||
supportFile: false,
|
||||
baseUrl: 'http://localhost:3001',
|
||||
},
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"plugins": ["cypress"],
|
||||
"extends": ["plugin:cypress/recommended"],
|
||||
"rules": {
|
||||
"jest/expect-expect": [
|
||||
"error",
|
||||
{
|
||||
"assertFunctionNames": ["expect", "cy.contains", "cy.**.should"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
describe('App', () => {
|
||||
it('should render the catalog', () => {
|
||||
cy.visit('/');
|
||||
cy.contains('My Company Catalog');
|
||||
});
|
||||
});
|
||||
+6
-5
@@ -14,9 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
describe('App', () => {
|
||||
it('should render the catalog', () => {
|
||||
cy.visit('/');
|
||||
cy.contains('My Company Service Catalog');
|
||||
});
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('App should render the welcome page', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
await expect(page.getByText('My Company Catalog')).toBeVisible();
|
||||
});
|
||||
@@ -11,11 +11,7 @@
|
||||
"build": "backstage-cli package build",
|
||||
"clean": "backstage-cli package clean",
|
||||
"test": "backstage-cli package test",
|
||||
"lint": "backstage-cli package lint",
|
||||
"test:e2e": "cross-env PORT=3001 start-server-and-test start http://localhost:3001 cy:dev",
|
||||
"test:e2e:ci": "cross-env PORT=3001 start-server-and-test start http://localhost:3001 cy:run",
|
||||
"cy:dev": "cypress open",
|
||||
"cy:run": "cypress run --browser chrome"
|
||||
"lint": "backstage-cli package lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/app-defaults": "^{{version '@backstage/app-defaults'}}",
|
||||
@@ -54,15 +50,13 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/test-utils": "^{{version '@backstage/test-utils'}}",
|
||||
"@playwright/test": "^1.32.3",
|
||||
"@testing-library/jest-dom": "^5.10.1",
|
||||
"@testing-library/react": "^12.1.3",
|
||||
"@testing-library/user-event": "^14.0.0",
|
||||
"@testing-library/dom": "^8.0.0",
|
||||
"@types/react-dom": "*",
|
||||
"cross-env": "^7.0.0",
|
||||
"cypress": "^12.0.0",
|
||||
"eslint-plugin-cypress": "^2.10.3",
|
||||
"start-server-and-test": "^1.10.11"
|
||||
"cross-env": "^7.0.0"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2023 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 { defineConfig } from '@playwright/test';
|
||||
import { generateProjects } from '@backstage/e2e-test-utils/playwright';
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
export default defineConfig({
|
||||
timeout: 60_000,
|
||||
|
||||
expect: {
|
||||
timeout: 5_000,
|
||||
},
|
||||
|
||||
// Run your local dev server before starting the tests
|
||||
webServer: process.env.CI
|
||||
? []
|
||||
: [
|
||||
{
|
||||
command: 'yarn start',
|
||||
port: 3000,
|
||||
reuseExistingServer: true,
|
||||
timeout: 60_000,
|
||||
},
|
||||
],
|
||||
|
||||
forbidOnly: !!process.env.CI,
|
||||
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
|
||||
reporter: [['html', { open: 'never', outputFolder: 'e2e-test-report' }]],
|
||||
|
||||
use: {
|
||||
actionTimeout: 0,
|
||||
baseURL:
|
||||
process.env.PLAYWRIGHT_URL ??
|
||||
(process.env.CI ? 'http://localhost:7007' : 'http://localhost:3000'),
|
||||
screenshot: 'only-on-failure',
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
|
||||
outputDir: 'node_modules/.cache/e2e-test-results',
|
||||
|
||||
projects: generateProjects(), // Find all packages with e2e-test folders
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
@@ -0,0 +1,12 @@
|
||||
# @backstage/e2e-test-utils
|
||||
|
||||
_This package was created through the Backstage CLI_.
|
||||
|
||||
## Installation
|
||||
|
||||
Install the package via Yarn:
|
||||
|
||||
```sh
|
||||
cd <package-dir> # if within a monorepo
|
||||
yarn add --dev @backstage/e2e-test-utils
|
||||
```
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: backstage-e2e-test-utils
|
||||
title: '@backstage/e2e-test-utils'
|
||||
description: Shared end-to-end test utilities Backstage
|
||||
spec:
|
||||
lifecycle: experimental
|
||||
type: backstage-node-library
|
||||
owner: maintainers
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"name": "@backstage/e2e-test-utils",
|
||||
"description": "Shared end-to-end test utilities Backstage",
|
||||
"version": "0.0.0",
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"license": "Apache-2.0",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"exports": {
|
||||
"./playwright": "./src/playwright/index.ts",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"playwright": [
|
||||
"src/playwright/index.ts"
|
||||
],
|
||||
"package.json": [
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
},
|
||||
"backstage": {
|
||||
"role": "node-library"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "backstage-cli package start",
|
||||
"build": "backstage-cli package build",
|
||||
"lint": "backstage-cli package lint",
|
||||
"test": "backstage-cli package test",
|
||||
"clean": "backstage-cli package clean",
|
||||
"prepack": "backstage-cli package prepack",
|
||||
"postpack": "backstage-cli package postpack"
|
||||
},
|
||||
"dependencies": {
|
||||
"@manypkg/get-packages": "^1.1.3",
|
||||
"fs-extra": "^10.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/cli-node": "workspace:^",
|
||||
"@types/fs-extra": "^9.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@playwright/test": "^1.32.3"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@playwright/test": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
## API Report File for "@backstage/e2e-test-utils"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { PlaywrightTestConfig } from '@playwright/test';
|
||||
|
||||
// @public
|
||||
export function failOnBrowserErrors(): void;
|
||||
|
||||
// @public
|
||||
export function generateProjects(): PlaywrightTestConfig['projects'];
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
* Copyright 2023 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.
|
||||
@@ -13,4 +13,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export default () => {};
|
||||
export {};
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
* Copyright 2023 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.
|
||||
@@ -13,5 +13,5 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/// <reference types="cypress" />
|
||||
import './commands';
|
||||
|
||||
export * from './playwright/index';
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2023 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 { test } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* Calling this at the top of your test file will ensure that tests fail if the browser
|
||||
* logs any errors or if there are any uncaught exceptions.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function failOnBrowserErrors(): void {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
page.on('pageerror', error => {
|
||||
throw new Error(`Uncaught exception on page, ${error}`);
|
||||
});
|
||||
|
||||
page.on('console', msg => {
|
||||
if (msg.type() === 'error') {
|
||||
throw new Error(`Unexpected console error message "${msg.text()}"`);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2023 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 fs from 'fs-extra';
|
||||
import { resolve as resolvePath } from 'path';
|
||||
import { PlaywrightTestConfig } from '@playwright/test';
|
||||
import { getPackagesSync } from '@manypkg/get-packages';
|
||||
import type { BackstagePackage } from '@backstage/cli-node';
|
||||
|
||||
/**
|
||||
* Generates a list of playwright projects by scanning the monorepo for packages with an `e2e-tests/` folder.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function generateProjects(): PlaywrightTestConfig['projects'] {
|
||||
// TODO(Rugvip): Switch this over to use @backstage/cli-node once released, and support SINCE=origin/main
|
||||
const { root, packages } = getPackagesSync(process.cwd());
|
||||
const e2eTestPackages = [...(root ? [root] : []), ...packages].filter(pkg => {
|
||||
return fs.pathExistsSync(resolvePath(pkg.dir, 'e2e-tests'));
|
||||
}) as BackstagePackage[];
|
||||
|
||||
return e2eTestPackages.map(pkg => ({
|
||||
name: pkg.packageJson.name,
|
||||
testDir: resolvePath(pkg.dir, 'e2e-tests'),
|
||||
use: {
|
||||
channel: 'chrome',
|
||||
},
|
||||
}));
|
||||
}
|
||||
+4
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
* Copyright 2023 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.
|
||||
@@ -13,7 +13,6 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
Cypress.Commands.add('enterAsGuest', () => {
|
||||
cy.visit('/');
|
||||
cy.get('button').contains('Enter').click();
|
||||
});
|
||||
|
||||
export { generateProjects } from './generateProjects';
|
||||
export { failOnBrowserErrors } from './failOnBrowserErrors';
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
* Copyright 2023 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.
|
||||
@@ -13,5 +13,4 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import '@testing-library/cypress/add-commands';
|
||||
import './commands';
|
||||
export {};
|
||||
@@ -37,7 +37,6 @@
|
||||
"handlebars": "^4.7.3",
|
||||
"mysql2": "^2.2.5",
|
||||
"pgtools": "^1.0.0",
|
||||
"puppeteer": "^17.0.0",
|
||||
"tree-kill": "^1.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -20,13 +20,11 @@ import fetch from 'cross-fetch';
|
||||
import handlebars from 'handlebars';
|
||||
import killTree from 'tree-kill';
|
||||
import { resolve as resolvePath, join as joinPath } from 'path';
|
||||
import puppeteer from 'puppeteer';
|
||||
import path from 'path';
|
||||
|
||||
import {
|
||||
spawnPiped,
|
||||
runPlain,
|
||||
waitForPageWithText,
|
||||
waitFor,
|
||||
waitForExit,
|
||||
print,
|
||||
@@ -42,6 +40,7 @@ const paths = findPaths(__dirname);
|
||||
|
||||
const templatePackagePaths = [
|
||||
'packages/cli/templates/default-plugin/package.json.hbs',
|
||||
'packages/create-app/templates/default-app/package.json.hbs',
|
||||
'packages/create-app/templates/default-app/packages/app/package.json.hbs',
|
||||
'packages/create-app/templates/default-app/packages/backend/package.json.hbs',
|
||||
];
|
||||
@@ -66,8 +65,11 @@ export async function run() {
|
||||
print('Creating a Backstage Backend Plugin');
|
||||
await createPlugin({ appDir, pluginId, select: 'backend-plugin' });
|
||||
|
||||
print('Starting the app');
|
||||
await testAppServe(pluginId, appDir);
|
||||
print(`Running 'yarn test:e2e' in newly created app with new plugin`);
|
||||
await runPlain(['yarn', 'test:e2e'], {
|
||||
cwd: appDir,
|
||||
env: { ...process.env, CI: undefined },
|
||||
});
|
||||
|
||||
if (
|
||||
Boolean(process.env.POSTGRES_USER) ||
|
||||
@@ -297,15 +299,6 @@ async function createApp(
|
||||
await runPlain(['yarn', cmd], { cwd: appDir });
|
||||
}
|
||||
|
||||
print(`Running 'yarn test:e2e:ci' in newly created app`);
|
||||
await runPlain(['yarn', 'test:e2e:ci'], {
|
||||
cwd: resolvePath(appDir, 'packages', 'app'),
|
||||
env: {
|
||||
...process.env,
|
||||
APP_CONFIG_app_baseUrl: '"http://localhost:3001"',
|
||||
},
|
||||
});
|
||||
|
||||
return appDir;
|
||||
} finally {
|
||||
child.kill();
|
||||
@@ -381,63 +374,6 @@ async function createPlugin(options: {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start serving the newly created app and make sure that the create plugin is rendering correctly
|
||||
*/
|
||||
async function testAppServe(pluginId: string, appDir: string) {
|
||||
const startApp = spawnPiped(['yarn', 'start'], {
|
||||
cwd: appDir,
|
||||
env: {
|
||||
...process.env,
|
||||
GITHUB_TOKEN: 'abc',
|
||||
},
|
||||
});
|
||||
|
||||
let successful = false;
|
||||
|
||||
let browser;
|
||||
try {
|
||||
for (let attempts = 1; ; attempts++) {
|
||||
try {
|
||||
browser = await puppeteer.launch();
|
||||
const page = await browser.newPage();
|
||||
|
||||
await page.goto('http://localhost:3000', { waitUntil: 'networkidle0' });
|
||||
|
||||
await waitForPageWithText(page, '/', 'My Company Catalog');
|
||||
await waitForPageWithText(
|
||||
page,
|
||||
`/${pluginId}`,
|
||||
`Welcome to ${pluginId}!`,
|
||||
);
|
||||
|
||||
print('Both App and Plugin loaded correctly');
|
||||
successful = true;
|
||||
break;
|
||||
} catch (error) {
|
||||
if (attempts >= 20) {
|
||||
throw new Error(`App serve test failed, ${error}`);
|
||||
}
|
||||
print(`App serve failed, trying again, ${error}`);
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
// Kill entire process group, otherwise we'll end up with hanging serve processes
|
||||
await new Promise<void>((res, rej) => {
|
||||
killTree(startApp.pid!, err => (err ? rej(err) : res()));
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await waitForExit(startApp);
|
||||
} catch (error) {
|
||||
if (!successful) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Drops PG databases */
|
||||
async function dropDB(database: string, client: string) {
|
||||
try {
|
||||
|
||||
@@ -22,7 +22,6 @@ import {
|
||||
ChildProcess,
|
||||
} from 'child_process';
|
||||
import { promisify } from 'util';
|
||||
import puppeteer from 'puppeteer';
|
||||
|
||||
const execFile = promisify(execFileCb);
|
||||
|
||||
@@ -125,50 +124,6 @@ export async function waitForExit(child: ChildProcess) {
|
||||
);
|
||||
}
|
||||
|
||||
export async function waitForPageWithText(
|
||||
page: puppeteer.Page,
|
||||
path: string,
|
||||
text: string,
|
||||
{ intervalMs = 1000, maxFindAttempts = 50 } = {},
|
||||
) {
|
||||
let findAttempts = 0;
|
||||
for (;;) {
|
||||
try {
|
||||
const waitTimeMs = intervalMs * (findAttempts + 1);
|
||||
console.log(`Attempting to load page at ${path}, waiting ${waitTimeMs}`);
|
||||
await new Promise(resolve => setTimeout(resolve, waitTimeMs));
|
||||
|
||||
await page.goto(`http://localhost:3000${path}`, {
|
||||
waitUntil: 'networkidle0',
|
||||
});
|
||||
|
||||
const match = await page.evaluate(
|
||||
textContent =>
|
||||
Array.from(document.querySelectorAll('*')).some(
|
||||
el => el.textContent === textContent,
|
||||
),
|
||||
text,
|
||||
);
|
||||
|
||||
if (!match) {
|
||||
throw new Error(`Expected to find text ${text}`);
|
||||
}
|
||||
|
||||
break;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
assertError(error);
|
||||
|
||||
findAttempts++;
|
||||
if (findAttempts >= maxFindAttempts) {
|
||||
throw new Error(
|
||||
`Failed to load page '${path}', max number of attempts reached`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function print(msg: string) {
|
||||
return process.stdout.write(`${msg}\n`);
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"baseUrl": "http://localhost:3001",
|
||||
"fixturesFolder": false,
|
||||
"pluginsFile": false
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"plugins": ["cypress"],
|
||||
"extends": ["plugin:cypress/recommended"],
|
||||
"rules": {
|
||||
"jest/expect-expect": [
|
||||
"error",
|
||||
{
|
||||
"assertFunctionNames": ["expect", "cy.contains", "cy.**.should"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -42,21 +42,14 @@
|
||||
"@testing-library/user-event": "^14.0.0",
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"cross-env": "^7.0.0",
|
||||
"cypress": "^10.0.0",
|
||||
"eslint-plugin-cypress": "^2.10.3",
|
||||
"start-server-and-test": "^1.10.11"
|
||||
"cross-env": "^7.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "backstage-cli package start --config ./app-config.yaml",
|
||||
"build": "backstage-cli package build --config ./app-config.yaml",
|
||||
"clean": "backstage-cli package clean",
|
||||
"test": "backstage-cli package test",
|
||||
"lint": "backstage-cli package lint",
|
||||
"test:e2e": "cross-env PORT=3001 start-server-and-test start http://localhost:3001 cy:dev",
|
||||
"test:e2e:ci": "cross-env PORT=3001 start-server-and-test start http://localhost:3001 cy:run",
|
||||
"cy:dev": "cypress open",
|
||||
"cy:run": "cypress run"
|
||||
"lint": "backstage-cli package lint"
|
||||
},
|
||||
"prettier": "@spotify/prettier-config",
|
||||
"browserslist": {
|
||||
|
||||
@@ -75,38 +75,3 @@ pip install mkdocs-techdocs-core
|
||||
```
|
||||
|
||||
Then run `yarn test`.
|
||||
|
||||
#### Cypress (Integration and Visual regression) tests
|
||||
|
||||
Running cypress tests requires you to run the CLI locally against our example docs.
|
||||
|
||||
Run the local version of techdocs-cli against the example docs:
|
||||
|
||||
```sh
|
||||
# From the root of this repository run
|
||||
# NOTE: This will build the techdocs-cli-embedded-app and copy the output into the cli dist directory
|
||||
yarn build --scope @techdocs/cli
|
||||
|
||||
# Navigate to the example project
|
||||
cd packages/techdocs-cli/src/example-docs
|
||||
|
||||
# Now execute the techdocs-cli serve command
|
||||
../../bin/techdocs-cli serve
|
||||
```
|
||||
|
||||
In another shell, run the cypress tests:
|
||||
|
||||
```sh
|
||||
# From the root of the project, navigate to the techdocs-cli package
|
||||
cd packages/techdocs-cli
|
||||
|
||||
# Run tests
|
||||
yarn test:cypress
|
||||
```
|
||||
|
||||
This will launch a cypress app where you can run the two different tests:
|
||||
|
||||
- `backstage_serve` - will run against the backstage server
|
||||
- `mkdocs_serve` - will run test against the mkdocs server
|
||||
|
||||
> If its the first time you run Cypress, it will run a "Verifying Cypress can run" step. This step can result in a "Cypress verification timed out" error. If that is the case, let the verification step run and then run the command again and it should succeed.
|
||||
|
||||
+1
-1
@@ -18,5 +18,5 @@ const path = require('path');
|
||||
|
||||
module.exports = require('@backstage/cli/config/jest').then(baseConfig => ({
|
||||
...baseConfig,
|
||||
rootDir: path.resolve(__dirname, 'e2e-tests'),
|
||||
rootDir: path.resolve(__dirname, 'cli-e2e-tests'),
|
||||
}));
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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 { defineConfig } from 'cypress';
|
||||
import { initPlugin } from '@frsource/cypress-plugin-visual-regression-diff/plugins';
|
||||
|
||||
module.exports = defineConfig({
|
||||
e2e: {
|
||||
setupNodeEvents(on, config) {
|
||||
initPlugin(on, config);
|
||||
},
|
||||
|
||||
excludeSpecPattern: ['**/__snapshots__/*', '**/__image_snapshots__/*'],
|
||||
},
|
||||
viewportWidth: 1920,
|
||||
viewportHeight: 1080,
|
||||
includeShadowDom: true,
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"plugins": ["cypress"],
|
||||
"extends": ["plugin:cypress/recommended"],
|
||||
"rules": {
|
||||
"jest/expect-expect": [
|
||||
"error",
|
||||
{
|
||||
"assertFunctionNames": ["expect", "cy.contains", "cy.document"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 66 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 167 KiB |
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
/// <reference types="cypress" />
|
||||
describe('TechDocs Live Preview - Backstage Serve', () => {
|
||||
it('successfully serves documentation', () => {
|
||||
cy.visit(`${Cypress.env('backstageBaseUrl')}/docs/default/component/local`);
|
||||
cy.contains('hello mock docs');
|
||||
});
|
||||
|
||||
it('successfully navigates to sub page of documentation', () => {
|
||||
cy.contains('SubDocs').click();
|
||||
cy.contains('Home 2').click();
|
||||
cy.contains(
|
||||
'This is an md file in another docs folder using the MkDocs Monorepo Plugin',
|
||||
);
|
||||
});
|
||||
|
||||
it('successfully renders all Backstage main elements', () => {
|
||||
cy.contains('header', 'Live preview environment');
|
||||
cy.get('[data-testid="sidebar-root"]')
|
||||
.children()
|
||||
.should('have.length.gt', 0);
|
||||
});
|
||||
|
||||
it('successfully renders all extracted MkDocs main elements', () => {
|
||||
// as it gets replaced by Backstage header
|
||||
cy.get('.md-header').should('have.length', 0);
|
||||
cy.get('.md-main').should('have.length', 1);
|
||||
cy.contains(
|
||||
'.md-main',
|
||||
'This is an md file in another docs folder using the MkDocs Monorepo Plugin',
|
||||
);
|
||||
cy.get('.md-sidebar.md-sidebar--primary').should('have.length', 1);
|
||||
cy.get('.md-sidebar.md-sidebar--primary').should('have.length', 1);
|
||||
cy.get('.md-footer').should('have.length', 1);
|
||||
});
|
||||
|
||||
it('matchImage - Backstage TechDocs Page', () => {
|
||||
cy.visit(
|
||||
`${Cypress.env('backstageBaseUrl')}/docs/default/component/local`,
|
||||
).then(() => {
|
||||
cy.document().matchImage();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
/// <reference types="cypress" />
|
||||
describe('TechDocs Live Preview - MkDocs Serve', () => {
|
||||
it('successfully serves documentation', () => {
|
||||
cy.visit(Cypress.env('mkdocsBaseUrl'));
|
||||
cy.contains('hello mock docs');
|
||||
});
|
||||
|
||||
it('successfully navigates to sub page of documentation', () => {
|
||||
cy.contains('SubDocs').click();
|
||||
cy.contains('Home 2').click();
|
||||
cy.contains(
|
||||
'This is an md file in another docs folder using the MkDocs Monorepo Plugin',
|
||||
);
|
||||
});
|
||||
|
||||
it('successfully renders all main elements', () => {
|
||||
cy.get('.md-header').should('have.length', 1);
|
||||
cy.get('.md-main').should('have.length', 1);
|
||||
cy.contains(
|
||||
'.md-main',
|
||||
'This is an md file in another docs folder using the MkDocs Monorepo Plugin',
|
||||
);
|
||||
cy.get('.md-sidebar.md-sidebar--primary').should('have.length', 1);
|
||||
cy.get('.md-sidebar.md-sidebar--primary').should('have.length', 1);
|
||||
cy.get('.md-footer').should('have.length', 1);
|
||||
});
|
||||
|
||||
it('matchImage - MkDocs Page', () => {
|
||||
cy.visit(Cypress.env('mkdocsBaseUrl')).then(() => {
|
||||
cy.document().matchImage();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 392 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 322 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB |
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 322 KiB |
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022 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.
|
||||
*/
|
||||
|
||||
// This example support/index.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands';
|
||||
import '@frsource/cypress-plugin-visual-regression-diff/commands';
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
@@ -27,9 +27,8 @@
|
||||
"clean": "backstage-cli package clean",
|
||||
"lint": "backstage-cli package lint",
|
||||
"test": "backstage-cli package test",
|
||||
"test:e2e": "backstage-cli test --config e2e-test.config.js",
|
||||
"test:e2e:ci": "backstage-cli test --config e2e-test.config.js --watchAll=false --ci",
|
||||
"test:cypress": "cypress open",
|
||||
"test:e2e": "backstage-cli test --config cli-e2e-test.config.js",
|
||||
"test:e2e:ci": "backstage-cli test --config cli-e2e-test.config.js --watchAll=false --ci",
|
||||
"prepack": "./scripts/prepack.sh"
|
||||
},
|
||||
"bin": {
|
||||
@@ -37,14 +36,12 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@frsource/cypress-plugin-visual-regression-diff": "^3.2.8",
|
||||
"@types/commander": "^2.12.2",
|
||||
"@types/fs-extra": "^9.0.6",
|
||||
"@types/http-proxy": "^1.17.4",
|
||||
"@types/node": "^18.17.8",
|
||||
"@types/serve-handler": "^6.1.0",
|
||||
"@types/webpack-env": "^1.15.3",
|
||||
"cypress": "^10.0.0",
|
||||
"find-process": "^1.4.5",
|
||||
"nodemon": "^3.0.1",
|
||||
"techdocs-cli-embedded-app": "link:../techdocs-cli-embedded-app",
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2023 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 { defineConfig } from '@playwright/test';
|
||||
import { generateProjects } from '@backstage/e2e-test-utils/playwright';
|
||||
|
||||
/**
|
||||
* See https://playwright.dev/docs/test-configuration.
|
||||
*/
|
||||
export default defineConfig({
|
||||
timeout: 30_000,
|
||||
|
||||
expect: {
|
||||
timeout: 5_000,
|
||||
},
|
||||
|
||||
// Run your local dev server before starting the tests
|
||||
webServer: process.env.CI
|
||||
? []
|
||||
: [
|
||||
{
|
||||
command: 'yarn start',
|
||||
port: 3000,
|
||||
reuseExistingServer: true,
|
||||
timeout: 60_000,
|
||||
},
|
||||
// TODO: Before encouraging e2e tests for backend we'll want to provide better utilities for mocking auth
|
||||
// {
|
||||
// command: 'yarn start-backend',
|
||||
// port: 7007,
|
||||
// reuseExistingServer: true,
|
||||
// timeout: 60_000,
|
||||
// },
|
||||
],
|
||||
|
||||
forbidOnly: !!process.env.CI,
|
||||
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
|
||||
reporter: [['html', { open: 'never', outputFolder: 'e2e-test-report' }]],
|
||||
|
||||
use: {
|
||||
actionTimeout: 0,
|
||||
baseURL:
|
||||
process.env.PLAYWRIGHT_URL ??
|
||||
(process.env.CI ? 'http://localhost:7007' : 'http://localhost:3000'),
|
||||
screenshot: 'only-on-failure',
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
|
||||
outputDir: 'node_modules/.cache/e2e-test-results',
|
||||
|
||||
projects: generateProjects(), // Find all packages with e2e-test folders
|
||||
});
|
||||
@@ -36,7 +36,7 @@ async function findLockFiles() {
|
||||
|
||||
if (!files.length) {
|
||||
// List all lock files that are in the root or in an immediate subdirectory
|
||||
files = ['yarn.lock', 'cypress/yarn.lock', 'microsite/yarn.lock'];
|
||||
files = ['yarn.lock', 'microsite/yarn.lock'];
|
||||
}
|
||||
|
||||
return files.map(file => ({
|
||||
|
||||
Reference in New Issue
Block a user