mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
e2e: creates a separate package for selectors (#23858)
* Initial commit * Chore: fixes after merge * Chore: removes todos * Chore: uncomment test * Chore: adds missing externals to rollup config * Refactor: selectors is master for everything * Docs: updates Docs * Chore: adds e2e-selectors to publish
This commit is contained in:
@@ -26,7 +26,8 @@ All the integration tests are located at `e2e/suite<x>/specs`. The page objects
|
||||
Here is a good introduction to e2e best practices: https://martinfowler.com/bliki/PageObject.html.
|
||||
|
||||
- `Selector`: A unique identifier that is used from the e2e framework to retrieve an element from the Browser
|
||||
- `Page`: An abstraction for an object that contains one or more `Selectors`
|
||||
- `Page`: An abstraction for an object that contains one or more `Selectors` with `visit` function to navigate to the page.
|
||||
- `Component`: An abstraction for an object that contains one or more `Selectors` but without `visit` function
|
||||
- `Flow`: An abstraction that contains a sequence of actions on one or more `Pages` that can be reused and shared between tests
|
||||
|
||||
## Basic example
|
||||
@@ -57,15 +58,13 @@ Now that we added the `aria-label` we suddenly get more information about this p
|
||||
The next step is to create a `Page` representation in our e2e test framework to glue the test with the real implementation using the `pageFactory` function. For that function we can supply a `url` and `selectors` like in the example below:
|
||||
|
||||
```typescript
|
||||
export const Login = pageFactory({
|
||||
export const Login = {
|
||||
url: "/login", // used when called from Login.visit()
|
||||
selectors: {
|
||||
username: "Username input field", // used when called from Login.username().type('Hello World')
|
||||
},
|
||||
});
|
||||
username: "Username input field", // used when called from Login.username().type('Hello World')
|
||||
};
|
||||
```
|
||||
|
||||
The next step is to add the `Login` page to the exported const `Pages` in `packages/grafana-e2e/src/pages/index.ts` so that it appears when we type `e2e.pages` in our IDE.
|
||||
The next step is to add the `Login` page to the exported const `Pages` in `packages/grafana-e2e-selectors/src/selectors/pages.ts` so that it appears when we type `e2e.pages` in our IDE.
|
||||
|
||||
```ecmascript 6
|
||||
export const Pages = {
|
||||
@@ -81,15 +80,15 @@ Now that we have a `Page` called `Login` in our `Pages` const we can use that to
|
||||
|
||||
```jsx harmony
|
||||
<div>
|
||||
<input type="text" className="gf-form-input login-form-input" aria-label={e2e.pages.Login.selectors.username} />
|
||||
<input type="text" className="gf-form-input login-form-input" aria-label={selectors.pages.Login.username} />
|
||||
</div>
|
||||
```
|
||||
|
||||
The last step in our example is to use our `Login` page as part of a test. The `pageFactory` function we used before gives us two things:
|
||||
The last step in our example is to use our `Login` page as part of a test.
|
||||
|
||||
- The `url` property is used whenever we call the `visit` function and is equivalent to the Cypress function [cy.visit()](https://docs.cypress.io/api/commands/visit.html#Syntax).
|
||||
> Best practice after calling `visit` is to always call `should` on a selector to prevent flaky tests when you try to access an element that isn't ready. For more information, refer to [Commands vs. assertions](https://docs.cypress.io/guides/core-concepts/retry-ability.html#Commands-vs-assertions).
|
||||
- Any defined selector in the `selectors` property can be accessed from the `Login` page by invoking it. This is equivalent to the result of the Cypress function [cy.get(...)](https://docs.cypress.io/api/commands/get.html#Syntax).
|
||||
- Any defined selector can be accessed from the `Login` page by invoking it. This is equivalent to the result of the Cypress function [cy.get(...)](https://docs.cypress.io/api/commands/get.html#Syntax).
|
||||
|
||||
```ecmascript 6
|
||||
describe('Login test', () => {
|
||||
@@ -123,17 +122,15 @@ Let's take a look at an example that uses the same `selector` for multiple items
|
||||
|
||||
Just as before in the basic example we'll start by creating a page abstraction using the `pageFactory` function:
|
||||
```typescript
|
||||
export const DataSources = pageFactory({
|
||||
export const DataSources = {
|
||||
url: '/datasources',
|
||||
selectors: {
|
||||
dataSources: (dataSourceName: string) => `Data source list item ${dataSourceName}`,
|
||||
},
|
||||
});
|
||||
dataSources: (dataSourceName: string) => `Data source list item ${dataSourceName}`,
|
||||
};
|
||||
````
|
||||
|
||||
You might have noticed that instead of a simple `string` as the `selector`, we're using a `function` that takes a string parameter as an argument and returns a formatted string using the argument.
|
||||
|
||||
Just as before we need to add the `DataSources` page to the exported const `Pages` in `packages/grafana-e2e/src/pages/index.ts`.
|
||||
Just as before we need to add the `DataSources` page to the exported const `Pages` in `packages/grafana-e2e-selectors/src/selectors/pages.ts`.
|
||||
|
||||
The next step is to use the `dataSources` selector function as in our example below:
|
||||
|
||||
@@ -142,7 +139,7 @@ The next step is to use the `dataSources` selector function as in our example be
|
||||
{dataSources.map(dataSource => (
|
||||
<li className="card-item-wrapper" key={dataSource.id}>
|
||||
<a className="card-item" href={`datasources/edit/${dataSource.id}`}>
|
||||
<div className="card-item-name" aria-label={e2e.pages.DataSources.selectors.dataSources(dataSource.name)}>
|
||||
<div className="card-item-name" aria-label={selectors.pages.DataSources.dataSources(dataSource.name)}>
|
||||
{dataSource.name}
|
||||
</div>
|
||||
</a>
|
||||
|
||||
Reference in New Issue
Block a user