Merge branch 'master' of github.com:spotify/backstage into blam/msw-adr
* 'master' of github.com:spotify/backstage: Documentation skeleton (#1617) [TechDocs] Use Backstage docs as example (#1625)
@@ -122,3 +122,6 @@ dist
|
||||
|
||||
# Temporary change files created by Vim
|
||||
*.swp
|
||||
|
||||
# MkDocs build output
|
||||
site
|
||||
|
||||
@@ -1,10 +1,92 @@
|
||||
# Documentation
|
||||
# Documentation structure
|
||||
|
||||
Check out <https://backstage.io> or see the table of contents below.
|
||||
**Note!** This documentation structure is very much work in progress. If (when,
|
||||
really 😆) you find broken links or missing content, please create an issue or,
|
||||
better yet, a pull request.
|
||||
|
||||
- [Architecture and Terminology](architecture-terminology.md)
|
||||
- [Getting Started](getting-started/README.md)
|
||||
- [References](reference/README.md)
|
||||
- [Publishing](publishing.md)
|
||||
- [Designing for Backstage](design.md)
|
||||
- [How to Add an Auth Provider](auth/add-auth-provider.md)
|
||||
- Overview
|
||||
- [What is Backstage?](overview/what-is-backstage.md)
|
||||
- [Architecture and terminology](overview/architecture-terminology.md)
|
||||
- [Roadmap](overview/roadmap.md)
|
||||
- Getting started
|
||||
- [Running Backstage locally](getting-started/index.md)
|
||||
- [Installation](getting-started/installation.md)
|
||||
- [Local development](getting-started/development-environment.md)
|
||||
- [Demo deployment](https://backstage-demo.roadie.io)
|
||||
- Production deployments
|
||||
- [Create an App](getting-started/create-an-app.md)
|
||||
- App configuration
|
||||
- [Configuring App with plugins](getting-started/configure-app-with-plugins.md)
|
||||
- [Customize the look-and-feel of your App](getting-started/customize-app-look-and-feel.md)
|
||||
- Deployment scenarios
|
||||
- [Kubernetes](getting-started/deployment-k8s.md)
|
||||
- [Other](getting-started/deployment-other.md)
|
||||
- Features
|
||||
- Software Catalog
|
||||
- [Overview](features/software-catalog/index.md)
|
||||
- [System model](features/software-catalog/system-model.md)
|
||||
- [YAML File Format](features/software-catalog/descriptor-format.md)
|
||||
- [Populating the catalog](features/software-catalog/populating.md)
|
||||
- [Extending the model](features/software-catalog/extending-the-model.md)
|
||||
- [External integrations](features/software-catalog/external-integrations.md)
|
||||
- [API](features/software-catalog/api.md)
|
||||
- Software creation templates
|
||||
- [Overview](features/software-templates/index.md)
|
||||
- [Configure templates](features/software-templates/configure-templates.md)
|
||||
- [Adding templates](features/software-templates/adding-templates.md)
|
||||
- Docs-like-code
|
||||
- [Overview](features/techdocs/README.md)
|
||||
- [Getting Started](features/techdocs/getting-started.md)
|
||||
- [Concepts](features/techdocs/concepts.md)
|
||||
- [Reading Documentation](features/techdocs/reading-documentation.md)
|
||||
- [Writing Documentation](features/techdocs/writing-documentation.md)
|
||||
- [Publishing Documentation](features/techdocs/publishing-documentation.md)
|
||||
- [Contributing](features/techdocs/contributing.md)
|
||||
- [Debugging](features/techdocs/debugging.md)
|
||||
- [FAQ](features/techdocs/FAQ.md)
|
||||
- Plugins
|
||||
- [Overview](plugins/index.md)
|
||||
- [Existing plugins](plugins/existing-plugins.md)
|
||||
- [Creating a new plugin](plugins/create-a-plugin.md)
|
||||
- [Developing a plugin](plugins/developing-plugins.md)
|
||||
- [Structure of a plugin](plugins/structure-of-a-plugin.md)
|
||||
- Backends and APIs
|
||||
- [Proxying](plugins/proxying.md)
|
||||
- [Backstage backend plugin](plugins/backend-plugin.md)
|
||||
- [Call existing API](plugins/call-existing-api.md)
|
||||
- Testing
|
||||
- [Overview](plugins/testing.md)
|
||||
- Publishing
|
||||
- [Open source and NPM](plugins/publishing.md)
|
||||
- [Private/internal (non-open source)](plugins/publish-private.md)
|
||||
- Authentication and identity
|
||||
- [Overview](auth/index.md)
|
||||
- [Add auth provider](auth/add-auth-provider.md)
|
||||
- [Auth backend](auth/auth-backend.md)
|
||||
- [OAuth](auth/oauth.md)
|
||||
- [Glossary](auth/glossary.md)
|
||||
- Designing for Backstage
|
||||
- [Backstage Design Language System (DLS)](dls/design.md)
|
||||
- [Storybook -- reusable UI components](dls/storybook.md)
|
||||
- [Figma resources](dls/figma.md)
|
||||
- API references
|
||||
- TypeScript API
|
||||
- [Utilities](api/utility-apis.md)
|
||||
- [createPlugin](reference/createPlugin.md)
|
||||
- [createPlugin-feature-flags](reference/createPlugin-feature-flags.md)
|
||||
- [createPlugin-router](reference/createPlugin-router.md)
|
||||
- Backend APIs
|
||||
- [Backend](api/backend.md)
|
||||
- Tutorials
|
||||
- [Overview](tutorials/index.md)
|
||||
- Architecture Decision Records (ADRs)
|
||||
- [Overview](architecture-decisions/index.md)
|
||||
- [ADR001 - Architecture Decision Record (ADR) log](architecture-decisions/adr001-add-adr-log.md)
|
||||
- [ADR002 - Default Software Catalog File Format](architecture-decisions/adr002-default-catalog-file-format.md)
|
||||
- [ADR003 - Avoid Default Exports and Prefer Named Exports](architecture-decisions/adr003-avoid-default-exports.md)
|
||||
- [ADR004 - Module Export Structure](architecture-decisions/adr004-module-export-structure.md)
|
||||
- [ADR005 - Catalog Core Entities](architecture-decisions/adr005-catalog-core-entities.md)
|
||||
- [ADR006 - Avoid React.FC and React.SFC](architecture-decisions/adr006-avoid-react-fc.md)
|
||||
- [Contribute](../CONTRIBUTING.md)
|
||||
- [Support](overview/support.md)
|
||||
- [FAQ](FAQ.md)
|
||||
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
@@ -1,6 +1,8 @@
|
||||
## Date: 2020-04-26
|
||||
# ADR001: Architecture Decision Record (ADR) log
|
||||
|
||||
## Title: Architecture Decision Record (ADR) log
|
||||
| Created | Status |
|
||||
| ---------- | ------ |
|
||||
| 2020-04-26 | Open |
|
||||
|
||||
## Decision: A decision was made to store ADRs in a log in the project repository
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# Architecture Decision Records (ADR)
|
||||
|
||||
The substantial architecture decisions made in the Backstage project lives here.
|
||||
For more information about ADRs, when to write them, and why, please see
|
||||
[this blog post](https://engineering.atspotify.com/2020/04/14/when-should-i-write-an-architecture-decision-record/).
|
||||
|
||||
Records are never deleted but can be marked as superseded by new decisions or
|
||||
deprecated.
|
||||
|
||||
Records should be stored under the `architecture-decisions` directory.
|
||||
|
||||
## Contributing
|
||||
|
||||
### Creating an ADR
|
||||
|
||||
- Copy `0000-template.md` to `docs/architecture-decisions/0000-my-decision.md`
|
||||
(my-decision should be descriptive. Do not assign an ADR number.)
|
||||
- Fill in the ADR following the guidelines in the template
|
||||
- Submit a pull request
|
||||
- Address and integrate feedback from the community
|
||||
- Eventually, assign a number
|
||||
- Add the full path of the ADR to the [`mkdocs.yml`](/mkdocs.yml)
|
||||
- Merge the pull request
|
||||
|
||||
## Superseding an ADR
|
||||
|
||||
If an ADR supersedes an older ADR then the older ADR's status is changed to
|
||||
superseded by ADR-XXXX and links to the new ADR.
|
||||
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 303 KiB After Width: | Height: | Size: 303 KiB |
@@ -65,6 +65,5 @@ instance of Backstage with your own plugins.
|
||||
- [Create a Backstage Plugin](create-a-plugin.md)
|
||||
- [Structure of a Plugin](structure-of-a-plugin.md)
|
||||
- [Utility APIs](utility-apis.md)
|
||||
- Using Backstage components (TODO)
|
||||
|
||||
[Back to Docs](../README.md)
|
||||
@@ -14,5 +14,3 @@ different ways.
|
||||
Spotify we have over 100 plugins built by over 50 different teams. It has been
|
||||
very powerful to get contributions from various infrastructure teams added
|
||||
into a single unified developer experience.
|
||||
|
||||
[Back to Docs](README.md)
|
||||
@@ -0,0 +1,36 @@
|
||||
# Project roadmap
|
||||
|
||||
We created Backstage about 4 years ago. While our internal version of Backstage
|
||||
has had the benefit of time to mature and evolve, the first iteration of our
|
||||
open source version is still nascent. We are envisioning three phases of the
|
||||
project and we have already begun work on various aspects of these phases:
|
||||
|
||||
- 🐣 **Phase 1:** Extensible frontend platform (Done ✅) - You will be able to
|
||||
easily create a single consistent UI layer for your internal infrastructure
|
||||
and tools. A set of reusable
|
||||
[UX patterns and components](http://storybook.backstage.io) help ensure a
|
||||
consistent experience between tools.
|
||||
|
||||
- 🐢 **Phase 2:** Service Catalog
|
||||
([alpha released](https://backstage.io/blog/2020/06/22/backstage-service-catalog-alpha)) -
|
||||
With a single catalog, Backstage makes it easy for a team to manage ten
|
||||
services — and makes it possible for your company to manage thousands of them.
|
||||
Developers can get a uniform overview of all their software and related
|
||||
resources, regardless of how and where they are running, as well as an easy
|
||||
way to onboard and manage those resources.
|
||||
|
||||
- 🐇 **Phase 3:** Ecosystem (later) - Everyone's infrastructure stack is
|
||||
different. By fostering a vibrant community of contributors we hope to provide
|
||||
an ecosystem of Open Source plugins/integrations that allows you to pick the
|
||||
tools that match your stack.
|
||||
|
||||
Check out our [Milestones](https://github.com/spotify/backstage/milestones) and
|
||||
open [RFCs](https://github.com/spotify/backstage/labels/rfc) how they relate to
|
||||
the three Phases outlined above.
|
||||
|
||||
Our vision for Backstage is for it to become the trusted standard toolbox (read:
|
||||
UX layer) for the open source infrastructure landscape. Think of it like
|
||||
Kubernetes for developer experience. We realize this is an ambitious goal. We
|
||||
can’t do it alone. If this sounds interesting or you'd like to help us shape our
|
||||
product vision, we'd love to talk. You can email me directly:
|
||||
[alund@spotify.com](mailto:alund@spotify.com).
|
||||
@@ -0,0 +1,18 @@
|
||||
# Support and community
|
||||
|
||||
- [Discord chatroom](https://discord.gg/MUpMjP2) - Get support or discuss the
|
||||
project
|
||||
- [Good First Issues](https://github.com/spotify/backstage/contribute) - Start
|
||||
here if you want to contribute
|
||||
- [RFCs](https://github.com/spotify/backstage/labels/rfc) - Help shape the
|
||||
technical direction
|
||||
- [FAQ](docs/FAQ.md) - Frequently Asked Questions
|
||||
- [Code of Conduct](CODE_OF_CONDUCT.md) - This is how we roll
|
||||
- [Blog](https://backstage.io/blog/) - Announcements and updates
|
||||
- [Newsletter](https://mailchi.mp/spotify/backstage-community)
|
||||
- Give us a star ⭐️ - If you are using Backstage or think it is an interesting
|
||||
project, we would love a star ❤️
|
||||
|
||||
Or, if you are an open source developer and are interested in joining our team,
|
||||
please reach out to
|
||||
[foss-opportunities@spotify.com ](mailto:foss-opportunities@spotify.com)
|
||||
@@ -0,0 +1,44 @@
|
||||
# [Backstage](https://backstage.io)
|
||||
|
||||

|
||||
|
||||
## What is Backstage?
|
||||
|
||||
[Backstage](https://backstage.io/) is an open platform for building developer
|
||||
portals. It’s based on the developer portal we’ve been using internally at
|
||||
Spotify for over four years. Backstage can be as simple as a services catalog or
|
||||
as powerful as the UX layer for your entire tech infrastructure.
|
||||
|
||||
For more information go to [backstage.io](https://backstage.io) or join our
|
||||
[Discord chatroom](https://discord.gg/EBHEGzX).
|
||||
|
||||
### Features
|
||||
|
||||
- Create and manage all of your organization’s software and microservices in one
|
||||
place.
|
||||
- Services catalog keeps track of all software and its ownership.
|
||||
- Visualizations provide information about your backend services and tooling,
|
||||
and help you monitor them.
|
||||
- A unified method for managing microservices offers both visibility and
|
||||
control.
|
||||
- Preset templates allow engineers to quickly create microservices in a
|
||||
standardized way
|
||||
([coming soon](https://github.com/spotify/backstage/milestone/11)).
|
||||
- Centralized, full-featured technical documentation with integrated tooling
|
||||
that makes it easy for developers to set up, publish, and maintain alongside
|
||||
their code ([coming soon](https://github.com/spotify/backstage/milestone/15)).
|
||||
|
||||
### Benefits
|
||||
|
||||
- For _engineering managers_, it allows you to maintain standards and best
|
||||
practices across the organization, and can help you manage your whole tech
|
||||
ecosystem, from migrations to test certification.
|
||||
- For _end users_ (developers), it makes it fast and simple to build software
|
||||
components in a standardized way, and it provides a central place to manage
|
||||
all projects and documentation.
|
||||
- For _platform engineers_, it enables extensibility and scalability by letting
|
||||
you easily integrate new tools and services (via plugins), as well as
|
||||
extending the functionality of existing ones.
|
||||
- For _everyone_, it’s a single, consistent experience that ties all your
|
||||
infrastructure tooling, resources, standards, owners, contributors, and
|
||||
administrators together in one place.
|
||||
@@ -0,0 +1,26 @@
|
||||
# Plugins
|
||||
|
||||
Backstage is a single-page application composed of a set of plugins.
|
||||
|
||||
Our goal for the plugin ecosystem is that the definition of a plugin is flexible
|
||||
enough to allow you to expose pretty much any kind of infrastructure or software
|
||||
development tool as a plugin in Backstage. By following strong
|
||||
[design guidelines](https://github.com/spotify/backstage/blob/master/docs/design.md)
|
||||
we ensure the the overall user experience stays consistent between plugins.
|
||||
|
||||

|
||||
|
||||
## Creating a plugin
|
||||
|
||||
To create a plugin, follow the steps outlined
|
||||
[here](https://github.com/spotify/backstage/blob/master/docs/getting-started/create-a-plugin.md).
|
||||
|
||||
## Suggesting a plugin
|
||||
|
||||
If you start developing a plugin that you aim to release as open source, we
|
||||
suggest that you create a new
|
||||
[new Issue](https://github.com/spotify/backstage/issues/new?template=plugin_template.md).
|
||||
This helps the community know what plugins are in development.
|
||||
|
||||
You can also use this process if you have an idea for a good plugin but you hope
|
||||
that someone else will pick up the work.
|
||||
@@ -0,0 +1,371 @@
|
||||
# Testing with Jest
|
||||
|
||||
Backstage uses [Jest](https://facebook.github.io/jest/) for all our unit testing
|
||||
needs.
|
||||
|
||||
Jest is a Facebook-built unit testing framework specifically built for React. It
|
||||
follows in the footsteps of other classic Node.js unit testing-related
|
||||
frameworks and libraries like [Mocha](https://mochajs.org/),
|
||||
[Jasmine](https://jasmine.github.io/), and [Chai](http://www.chaijs.com/).
|
||||
|
||||
## Running Tests
|
||||
|
||||
Running all tests:
|
||||
|
||||
yarn test-react
|
||||
|
||||
Running an individual test (e.g. `MyComponent.test.js`):
|
||||
|
||||
yarn test-react MyComponent
|
||||
|
||||
To run both `MyComponent.test.js` and `MyControl.test.js` suite of tests:
|
||||
|
||||
yarn test-react MyCo
|
||||
|
||||
Note: if `console.logs` are not appearing, run only the individual test you are
|
||||
working on.
|
||||
[This is a bug in Jest](https://github.com/facebook/jest/issues/2441).
|
||||
|
||||
## Naming Test Files
|
||||
|
||||
Tests should be name `[filename].test.js`.
|
||||
|
||||
For example, the tests for **`Link.js`** exist in the file **`Link.test.js`**.
|
||||
|
||||
## Third-Party Dependencies
|
||||
|
||||
Jest has its own built-in assertion library with `expect`, so there is no need
|
||||
to `import` a third-party library like some of the older frameworks required.
|
||||
However since assertion libraries simply throw errors, it would be feasible to
|
||||
import a third-party library if you needed (like Chai or
|
||||
[Sinon](http://sinonjs.org/)).
|
||||
|
||||
We use the light-weight
|
||||
[react-testing-library](https://github.com/kentcdodds/react-testing-library) to
|
||||
render React components.
|
||||
|
||||
## Testing Utilities
|
||||
|
||||
TODO.
|
||||
|
||||
# Writing Unit Tests
|
||||
|
||||
The following principles are good guides to determining if you are writing high
|
||||
quality frontend unit tests.
|
||||
|
||||
## Bad Unit Test Principle
|
||||
|
||||
> No unit test is better than a bad one.
|
||||
|
||||
Writing a poor unit test:
|
||||
|
||||
- Gives the illusion your code is more secure or reliable than it actually is.
|
||||
- Functions equivalent to a bad comment, in that it leads the next developer
|
||||
into erroneous assumptions.
|
||||
- Adds to future work by requiring updates to the unit test for irrelevant code
|
||||
changes.
|
||||
|
||||
## Input/Output Principle
|
||||
|
||||
> A unit test verifies an output matches an expected input.
|
||||
|
||||
For backend, this would be that when you provide configuration X, then the
|
||||
object responds with Y. For frontend, this would be that when you provide
|
||||
properties X to a component, then the visual functionality responds with Y.
|
||||
|
||||
## Blackbox Principle
|
||||
|
||||
> A good unit test does not tell the object how it should do its job but should
|
||||
> only compare inputs to outputs.
|
||||
|
||||
Consider a unit test for a form. A good unit test would not test the order of
|
||||
the form fields. Instead, it would verify that the inputs to the form fields
|
||||
lead to a certain backend call when submit is clicked.
|
||||
|
||||
## Scalability Principle
|
||||
|
||||
> Unit test quality is directly proportionate to how much code can change
|
||||
> without having to touch the unit test.
|
||||
|
||||
This is often overlooked! A unit test is not a test to verify the code never
|
||||
changes. Poor unit tests are written so that every time you make a tiny change
|
||||
to the code, you have to update the unit test. A good unit test suite allows a
|
||||
lot of flexibility in _how_ the code is written so that future refactoring can
|
||||
occur without having to touch the original unit tests.
|
||||
|
||||
## Increasing Complexity Principle
|
||||
|
||||
> The ordering of unit tests in a suite should proceed from least specific to
|
||||
> most specific.
|
||||
|
||||
Jest runs all tests in the order in which they are provided, regardless of the
|
||||
depth of `describe()` blocks you provide. We can use this to help us write tests
|
||||
that will help the next developer debug what they broke.
|
||||
|
||||
The idea here is that if they were to break a unit test, the next developer
|
||||
should be able to tell from the order in which the tests broke what they should
|
||||
do to fix things.
|
||||
|
||||
For example, good unit tests will verify the arguments to a function in a test
|
||||
prior to a test that validates the output. If you do not test this, then simply
|
||||
throwing an error saying that output was incorrect will lead the next developer
|
||||
into thinking they may have broken the entire functionality of the object rather
|
||||
than simply letting them know they had an invalid input.
|
||||
|
||||
## Broken Functionality Principle
|
||||
|
||||
> Generally, a unit test should not test exactly how the output appears, it
|
||||
> should test that the functionality has an expected _general_ response to an
|
||||
> input change.
|
||||
|
||||
This piggybacks the Scalability Principle and applies primarily to frontend
|
||||
development. As a general rule of thumb, frontends should be flexible enough so
|
||||
that the UX or design can change while touching the least amount of code
|
||||
possible. So for example, a poor unit test would verify the color of a button
|
||||
when it is hovered. This would be a poor unit test, because if you decide to
|
||||
test a slightly different color on the button the unit test will break. A better
|
||||
unit test would verify that the button's CSS classname is assigned properly on
|
||||
hover or test for something completely different.
|
||||
|
||||
## Example: Loading Indicator
|
||||
|
||||
A classic unit test on frontends is verifying a loading indicator displays when
|
||||
a backend request is being made.
|
||||
|
||||
**Here are some things we could test for _when data is loading_:**
|
||||
|
||||
> Did the internal `loading` state of the component change? (poor)
|
||||
|
||||
This is not a great test because it does not actually test that the
|
||||
functionality (displaying a message to the user) actually happens. It also
|
||||
breaks the Blackbox Principle by expecting the internals of the component must
|
||||
work a certain way. This could be a good test on its own right, but it does not
|
||||
actually achieve the goal of verifying that if our input (loading data) occurs,
|
||||
then the output (displaying a message to the user) has happened.
|
||||
|
||||
> Did the text `"Loading!"` appear in the DOM? (better)
|
||||
|
||||
This is a better test because it validates functionality, but it breaks the
|
||||
Scalability principle. By testing for `'Loading...'` we are linking our test
|
||||
code to the component's message. If we want to add internationalization or
|
||||
simply change the message to something more specific we will break our test and
|
||||
have to update code in two places.
|
||||
|
||||
> Did `<Loading />` get mounted? (best)
|
||||
|
||||
This is the best test of these examples (there could be more depending on your
|
||||
implementation).
|
||||
|
||||
Verifying that `<Loading />` is mounted when data is loading is the best test
|
||||
because it fulfills all the principles above:
|
||||
|
||||
✓ **Fulfills Input/Output Principle**: Verifies the output changes when the
|
||||
input changes
|
||||
|
||||
✓ **Fufills Blackbox Principle**: Does not verify _how_ the `<Loading />`
|
||||
component is mounted, just that it is mounted in response to the input.
|
||||
|
||||
✓ **Fulfills Scalability Principle**: If we decide to refactor the entire way
|
||||
the loading indicator is displayed the test still works without touching it.
|
||||
|
||||
✓ **Fulfills Broken Functionality Principle**: this test verifies the
|
||||
functionality (displaying an indicator) is working, rather than how it is
|
||||
working.
|
||||
|
||||
The increasing complexity principle does not really apply to this example, so it
|
||||
was excluded. However if you were to place this test in a suite of other tests,
|
||||
it would be best to test first that when the component is instructed to load
|
||||
data then it actually does it. this way both tests fail if the data loading part
|
||||
breaks and the next developer immediately know the problem is that the data
|
||||
loading is broken, not that the loading indicator is broken.
|
||||
|
||||
# Examples
|
||||
|
||||
## Utility Functions
|
||||
|
||||
A utility function is a function with no side effects. It takes in arguments and
|
||||
returns a result or displays an error or console message, like so:
|
||||
|
||||
**`StringUtil ellipsis`**
|
||||
|
||||
export function ellipsis(text, maxLength, midCharIx = 0, ellipsis = '...') {
|
||||
// Do something blackbox. We should not care about the internals, only inputs and outputs.
|
||||
...
|
||||
return someFinalValue;
|
||||
}
|
||||
|
||||
There are four things to test for in a utility function:
|
||||
|
||||
1. Handle Invalid Input
|
||||
2. Verify default input arguments
|
||||
3. Verify output for expected input arguments
|
||||
4. Handle thrown errors
|
||||
|
||||
> Handle Invalid Input (handle thrown errors):
|
||||
|
||||
it('Throws an error on improper arguments', () => {
|
||||
expect(() => {
|
||||
ellipsis();
|
||||
}).toThrowError('Expected \'text\' to be defined');
|
||||
});
|
||||
|
||||
> Verify default input arguments:
|
||||
|
||||
it('Works with defaults', () => {
|
||||
expect(ellipsis('Hello world', 3)).toBe('Hel...');
|
||||
expect(ellipsis('', 3)).toBe('');
|
||||
expect(ellipsis('H', 3)).toBe('H');
|
||||
expect(ellipsis('Hello', 5)).toBe('Hello');
|
||||
});
|
||||
|
||||
> Verify output for expected input arguments:
|
||||
|
||||
This is especially true for edge cases!
|
||||
|
||||
it('Works with midCharIx', () => {
|
||||
expect(ellipsis('Hello world', 3, 6)).toBe('...o w...');
|
||||
expect(ellipsis('', 3, 6)).toBe('');
|
||||
expect(ellipsis('Backstage is amazing', 4, 10)).toBe('...e is...');
|
||||
});
|
||||
|
||||
## Non-React Classes
|
||||
|
||||
Testing a Javascript object which is _not_ a React component follows a lot of
|
||||
the same principles as testing objects in other languages.
|
||||
|
||||
### API Testing Principles
|
||||
|
||||
Testing an API involves verifying four things:
|
||||
|
||||
1. Invalid inputs are caught before being sent to the server.
|
||||
2. Valid inputs translate into a valid browser request.
|
||||
3. Server response is translated into an expected Javascript object.
|
||||
4. Server errors are handled gracefully.
|
||||
|
||||
### Mocking API Calls
|
||||
|
||||
[Mocking in jest](https://facebook.github.io/jest/docs/en/mock-functions.html)
|
||||
involves wrapping existing functions (like an API call function) with an
|
||||
alternative.
|
||||
|
||||
For example:
|
||||
|
||||
**./Api.js**
|
||||
|
||||
```
|
||||
export {
|
||||
fetchSomethingFromServer: () => {
|
||||
// Live production call to a URI. Must be avoided during testing!
|
||||
return fetch('blah');
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**./\_\_mocks\_\_/Api.js**
|
||||
|
||||
```
|
||||
export {
|
||||
fetchSomethingFromServer: () => {
|
||||
// Simulate a production call, but avoid jest and just use a promise
|
||||
return Promise.resolve('some result object simulating server data here');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**./Api.test.js**
|
||||
|
||||
```
|
||||
/* eslint-disable import/first */
|
||||
|
||||
jest.mock('./MyApi'); // Instruct Jest to swap all future imports of './MyApi.js' to './__mocks__/MyApi.js'
|
||||
|
||||
import MyApi from './MyApi'; // Will actually return the contents of the file in the __mocks__ folder now
|
||||
|
||||
it ('loads data', (done) => {
|
||||
MyApi.fetchSomethingFromServer().then(result => {
|
||||
expect(result).toBe('some result object simulating server data here');
|
||||
done();
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
Note: make sure you disable the eslint `'import/first'` rule at the top of the
|
||||
file since technically you are not allowed by the default settings to have an
|
||||
import after the `jest.mock` call.
|
||||
|
||||
## React Components
|
||||
|
||||
### Working with the React Lifecycle
|
||||
|
||||
The [React lifecycle](https://reactjs.org/docs/state-and-lifecycle.html) is
|
||||
asynchronous.
|
||||
|
||||
When you call `setState` or update the `props` of a component, there are several
|
||||
asynchronous stages that must occur before a rerender. Note the following
|
||||
example:
|
||||
|
||||
```jsx
|
||||
class MyComponent extends Component {
|
||||
load() {
|
||||
this.setState({loading: true});
|
||||
}
|
||||
|
||||
render() {
|
||||
return this.state.loading ? <Loading /> : 'Finished!';
|
||||
}
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
// INCORRECT
|
||||
it('Test loading', () => {
|
||||
const wrapper = mount(<MyComponent />);
|
||||
wrapper.load();
|
||||
expect(wrapper.find('Loading').length).toEqual(1); // Will fail
|
||||
});
|
||||
|
||||
// CORRECT
|
||||
it('Test loading', () => {
|
||||
const wrapper = mount(<MyComponent />);
|
||||
wrapper.load();
|
||||
wrapper.update(); // This tells the components to run through a render cycle
|
||||
expect(wrapper.find('Loading').length).toEqual(1);
|
||||
});
|
||||
```
|
||||
|
||||
For more information:
|
||||
|
||||
- [React lifecycle](https://reactjs.org/docs/state-and-lifecycle.html)
|
||||
|
||||
### Accessing `store`, `theme`, routing, browser history, etc.
|
||||
|
||||
The Backstage application has several core providers at its root. To run your
|
||||
test wrapped in a "dummy" Backstage application, you can use our utility
|
||||
functions:
|
||||
|
||||
**`wrapInTestApp`**
|
||||
|
||||
import { wrapInTestApp } from '../../test-utils';
|
||||
...
|
||||
it('Definitely is not a coconut', () => {
|
||||
const mangoWrapper = mount(wrapInTestApp(<Mango />));
|
||||
|
||||
expect(mangoWrapper.context().store).toBeDefined();
|
||||
});
|
||||
|
||||
Note: wrapping in the test application **requires** you to do a `find()` or
|
||||
`dive()` since the wrapped component is now the application.
|
||||
|
||||
# Debugging Jest Tests
|
||||
|
||||
Currently, debugging Jest tests using IntelliJ or `node-debugger` is possible
|
||||
but can be
|
||||
[problematic to set up.](https://intellij-support.jetbrains.com/hc/en-us/community/posts/115000634564-Debugging-Jest-unit-tests)
|
||||
|
||||
It is possible, but you might spend a decent amount of time configuring your
|
||||
IDE.
|
||||
|
||||
In most cases, we have found that using `console.log` works well.
|
||||
|
||||
Note: if your console.logs are not being displayed, focus your specific unit
|
||||
test from the command line by running them like so `yarn test-react MyTest`.
|
||||
@@ -1,9 +0,0 @@
|
||||
# Reference documentation
|
||||
|
||||
APIs and Components
|
||||
|
||||
- [createPlugin](createPlugin.md)
|
||||
- [createPlugin - router](createPlugin-router.md)
|
||||
- [createPlugin - feature flags](createPlugin-feature-flags.md)
|
||||
|
||||
[Back to Docs](../README.md)
|
||||
@@ -64,5 +64,3 @@ const ExampleButton: FC<{}> = () => {
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
[Back to References](README.md)
|
||||
|
||||
@@ -39,5 +39,3 @@ export default createPlugin({
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
[Back to References](README.md)
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
site_name: 'Backstage'
|
||||
site_description: 'Main documentation for Backstage features and platform APIs'
|
||||
|
||||
nav:
|
||||
- Overview:
|
||||
- What is Backstage?: 'overview/what-is-backstage.md'
|
||||
- Architecture and terminology: 'overview/architecture-terminology.md'
|
||||
- Roadmap: 'overview/roadmap.md'
|
||||
- Getting started:
|
||||
- Running Backstage locally: 'getting-started/index.md'
|
||||
- Installation: 'getting-started/installation.md'
|
||||
- Local development: 'getting-started/development-environment.md'
|
||||
- Demo deployment: https://backstage-demo.roadie.io
|
||||
- Production deployments:
|
||||
- Create an App: 'getting-started/create-an-app.md'
|
||||
- App configuration:
|
||||
- Configuring App with plugins: 'getting-started/configure-app-with-plugins.md'
|
||||
- Customize the look-and-feel of your App: 'getting-started/customize-app-look-and-feel.md'
|
||||
- Deployment scenarios:
|
||||
- Kubernetes: 'getting-started/deployment-k8s.md'
|
||||
- Other: 'getting-started/deployment-other.md'
|
||||
- Features:
|
||||
- Software Catalog:
|
||||
- Overview: 'features/software-catalog/index.md'
|
||||
- System model: 'features/software-catalog/system-model.md'
|
||||
- YAML File Format: 'features/software-catalog/descriptor-format.md'
|
||||
- Populating the catalog: 'features/software-catalog/populating.md'
|
||||
- Extending the model: 'features/software-catalog/extending-the-model.md'
|
||||
- External integrations: 'features/software-catalog/external-integrations.md'
|
||||
- API: 'features/software-catalog/api.md'
|
||||
- Software creation templates:
|
||||
- Overview: 'features/software-templates/index.md'
|
||||
- Configure templates: 'features/software-templates/configure-templates.md'
|
||||
- Adding templates: 'features/software-templates/adding-templates.md'
|
||||
- Docs-like-code:
|
||||
- Overview: 'features/techdocs/README.md'
|
||||
- Getting Started: 'features/techdocs/getting-started.md'
|
||||
- Concepts: 'features/techdocs/concepts.md'
|
||||
- Reading Documentation: 'features/techdocs/reading-documentation.md'
|
||||
- Writing Documentation: 'features/techdocs/writing-documentation.md'
|
||||
- Publishing Documentation: 'features/techdocs/publishing-documentation.md'
|
||||
- Contributing: 'features/techdocs/contributing.md'
|
||||
- Debugging: 'features/techdocs/debugging.md'
|
||||
- FAQ: 'features/techdocs/FAQ.md'
|
||||
- Plugins:
|
||||
- Overview: 'plugins/index.md'
|
||||
- Existing plugins: 'plugins/existing-plugins.md'
|
||||
- Creating a new plugin: 'plugins/create-a-plugin.md'
|
||||
- Developing a plugin: 'plugins/developing-plugins.md'
|
||||
- Structure of a plugin: 'plugins/structure-of-a-plugin.md'
|
||||
- Backends and APIs:
|
||||
- Proxying: 'plugins/proxying.md'
|
||||
- Backstage backend plugin: 'plugins/backend-plugin.md'
|
||||
- Call existing API: 'plugins/call-existing-api.md'
|
||||
- Testing:
|
||||
- Overview: 'plugins/testing.md'
|
||||
- Publishing:
|
||||
- Open source and NPM: 'plugins/publishing.md'
|
||||
- Private/internal (non-open source): 'plugins/publish-private.md'
|
||||
- Authentication and identity:
|
||||
- Overview: 'auth/index.md'
|
||||
- Add auth provider: 'auth/add-auth-provider.md'
|
||||
- Auth backend: 'auth/auth-backend.md'
|
||||
- OAuth: 'auth/oauth.md'
|
||||
- Glossary: 'auth/glossary.md'
|
||||
- Designing for Backstage:
|
||||
- Backstage Design Language System (DLS): 'dls/design.md'
|
||||
- Storybook -- reusable UI components: 'dls/storybook.md'
|
||||
- Figma resources: 'dls/figma.md'
|
||||
- API references:
|
||||
- TypeScript APIs:
|
||||
- Utilities: 'api/utility-apis.md'
|
||||
- createPlugin: 'reference/createPlugin.md'
|
||||
- createPlugin-feature-flags: 'reference/createPlugin-feature-flags.md'
|
||||
- createPlugin-router: 'reference/createPlugin-router.md'
|
||||
- Backend APIs:
|
||||
- Backend: 'api/backend.md'
|
||||
- Tutorials:
|
||||
- Overview: 'tutorials/index.md'
|
||||
- Architecture Decision Records (ADRs):
|
||||
- Overview: 'architecture-decisions/index.md'
|
||||
- ADR001 - Architecture Decision Record (ADR) log: 'architecture-decisions/adr001-add-adr-log.md'
|
||||
- ADR002 - Default Software Catalog File Format: 'architecture-decisions/adr002-default-catalog-file-format.md'
|
||||
- ADR003 - Avoid Default Exports and Prefer Named Exports: 'architecture-decisions/adr003-avoid-default-exports.md'
|
||||
- ADR004 - Module Export Structure: 'architecture-decisions/adr004-module-export-structure.md'
|
||||
- ADR005 - Catalog Core Entities: 'architecture-decisions/adr005-catalog-core-entities.md'
|
||||
- ADR006 - Avoid React.FC and React.SFC: 'architecture-decisions/adr006-avoid-react-fc.md'
|
||||
- Contribute: '../CONTRIBUTING.md'
|
||||
- Support: 'overview/support.md'
|
||||
- FAQ: FAQ.md
|
||||
|
||||
plugins:
|
||||
- techdocs-core
|
||||
@@ -39,10 +39,9 @@ const documentationSites: Array<DocumentationSite> = [
|
||||
},
|
||||
{
|
||||
title: 'Backstage Docs',
|
||||
description:
|
||||
'Getting started guides, API Overview, documentation around how to Create a Plugin and more. ',
|
||||
description: 'Main documentation for Backstage features and platform APIs.',
|
||||
tags: ['Service'],
|
||||
path: '/docs/backstage-microsite',
|
||||
path: '/docs/backstage',
|
||||
btnLabel: 'Read Docs',
|
||||
},
|
||||
];
|
||||
|
||||