diff --git a/contribute/style-guides/e2e.md b/contribute/style-guides/e2e.md index 0aed129f1e3..61d90338419 100644 --- a/contribute/style-guides/e2e.md +++ b/contribute/style-guides/e2e.md @@ -1,9 +1,9 @@ # End to end test framework -Grafana Labs uses a minimal home grown solution built on top of Cypress for our end to end (e2e) tests. +Grafana Labs uses a minimal home grown solution built on top of Cypress for our end to end (e2e) tests. ## Basic concepts 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 +- `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` - `Flow`: An abstraction that contains a sequence of actions on one or more `Pages` that can be reused and shared between tests @@ -49,16 +49,16 @@ export const Pages = { }; ``` -Now that we have a `Page` called `Login` in our `Pages` const we can use that to add a selector in our html like shown below and now this really signals to future developers that it is part of an e2e test. +Now that we have a `Page` called `Login` in our `Pages` const we can use that to add a selector in our html like shown below and now this really signals to future developers that it is part of an e2e test. ```jsx harmony
``` -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 `pageFactory` function we used before gives us two things: - 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). +> 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). ```ecmascript 6 describe('Login test', () => { @@ -90,7 +90,7 @@ 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: +Just as before in the basic example we'll start by creating a page abstraction using the `pageFactory` function: ```typescript export const DataSources = pageFactory({ url: '/datasources', @@ -134,15 +134,27 @@ When this list is rendered with the data sources with names `A`, `B`, `C` the re ``` Now we can write our test. The one thing that differs from the `Basic example` is that we pass in which data source we want to click on as an argument to the selector function: -> 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). +> 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). ```ecmascript 6 describe('List test', () => { it('Clicking on data source named B', () => { e2e.pages.DataSources.visit(); // To prevent flaky tests, always do a .should on any selector that you expect to be in the DOM. // Read more here: https://docs.cypress.io/guides/core-concepts/retry-ability.html#Commands-vs-assertions - e2e.pages.DataSources.dataSources('B').should('be.visible'); + e2e.pages.DataSources.dataSources('B').should('be.visible'); e2e.pages.DataSources.dataSources('B').click(); }); }); ``` + + +## Debugging PhantomJS image rendering + +There is no easy or comprehensive way to debug PhantomJS smoke test (image rendering) failures. However, PhantomJS exposes remote debugging interface which can give you a sense of what is going wrong in the smoke test. Before performing the steps described below make sure your local Grafana instance is running: + +1. Go to `tools/phantomjs` directory +2. Execute `phantomjs` binary against `render.js` file: `./phantomjs --remote-debugger-port=9009 --remote-debugger-autorun=yes ./render.js url="http://localhost:3000"` +3. In your browser navigate to `http://localhost:9009/` +4. Select `http://localhost:3000/login` from the list. You will get access to Webkit's inspector to see the console's output from the smoke test. + +The method described above is not perfect, but is helpful to evaluate smoke tests breaking due to bundle errors.