mirror of https://github.com/grafana/grafana.git
				
				
				
			@grafana/e2e: API improvements (#23079)
* Minor changes * Fixtures path is now relative to the project directory * URL support module now has individual exports * Scenario context timing issues resolved ... caused by being ran synchronously, instead of as part of Cypress' asynchronous queue. * Scenario context API now supports multiple keys per function call * addDataSource flow accepts a config argument … and optionally checks datasource health status * Added readProvisions command * Added addPanel flow
This commit is contained in:
		
							parent
							
								
									13ab84f201
								
							
						
					
					
						commit
						a4308fffe7
					
				|  | @ -190,13 +190,17 @@ const assertAdding3dependantQueryVariablesScenario = (queryVariables: QueryVaria | |||
|   for (let queryVariableIndex = 0; queryVariableIndex < queryVariables.length; queryVariableIndex++) { | ||||
|     const { name, label, query, options, selectedOption } = queryVariables[queryVariableIndex]; | ||||
|     const asserts = queryVariables.slice(0, queryVariableIndex + 1); | ||||
|     createQueryVariable({ | ||||
|       dataSourceName: e2e.context().get('lastAddedDataSource'), | ||||
|       name, | ||||
|       label, | ||||
|       query, | ||||
|       options, | ||||
|       selectedOption, | ||||
|     // @todo remove `@ts-ignore` when possible
 | ||||
|     // @ts-ignore
 | ||||
|     e2e.getScenarioContext().then(({ lastAddedDataSource }) => { | ||||
|       createQueryVariable({ | ||||
|         dataSourceName: lastAddedDataSource, | ||||
|         name, | ||||
|         label, | ||||
|         query, | ||||
|         options, | ||||
|         selectedOption, | ||||
|       }); | ||||
|     }); | ||||
| 
 | ||||
|     assertVariableTable(asserts); | ||||
|  | @ -565,7 +569,11 @@ e2e.scenario({ | |||
|   addScenarioDashBoard: true, | ||||
|   skipScenario: false, | ||||
|   scenario: () => { | ||||
|     e2e.flows.openDashboard(e2e.context().get('lastAddedDashboardUid')); | ||||
|     // @todo remove `@ts-ignore` when possible
 | ||||
|     // @ts-ignore
 | ||||
|     e2e.getScenarioContext().then(({ lastAddedDashboardUid }) => { | ||||
|       e2e.flows.openDashboard(lastAddedDashboardUid); | ||||
|     }); | ||||
|     e2e.pages.Dashboard.Toolbar.toolbarItems('Dashboard settings').click(); | ||||
|     e2e.pages.Dashboard.Settings.General.sectionItems('Variables').click(); | ||||
|     e2e.pages.Dashboard.Settings.Variables.List.addVariableCTA().click(); | ||||
|  |  | |||
|  | @ -7,7 +7,11 @@ e2e.scenario({ | |||
|   addScenarioDashBoard: true, | ||||
|   skipScenario: false, | ||||
|   scenario: () => { | ||||
|     e2e.flows.openDashboard(e2e.context().get('lastAddedDashboardUid')); | ||||
|     // @todo remove `@ts-ignore` when possible
 | ||||
|     // @ts-ignore
 | ||||
|     e2e.getScenarioContext().then(({ lastAddedDashboardUid }) => { | ||||
|       e2e.flows.openDashboard(lastAddedDashboardUid); | ||||
|     }); | ||||
|     e2e.pages.Dashboard.Toolbar.toolbarItems('Add panel').click(); | ||||
|     e2e.pages.AddDashboard.ctaButtons('Add Query').click(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ module.exports = async baseConfig => { | |||
| 
 | ||||
|   if (CWD) { | ||||
|     const projectConfig = { | ||||
|       fixturesFolder: `${CWD}/cypress/fixtures`, | ||||
|       integrationFolder: `${CWD}/cypress/integration`, | ||||
|       screenshotsFolder: `${CWD}/cypress/screenshots`, | ||||
|       videosFolder: `${CWD}/cypress/videos`, | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| const compareSnapshotsPlugin = require('./compareSnapshots'); | ||||
| const extendConfig = require('./extendConfig'); | ||||
| const readProvisions = require('./readProvisions'); | ||||
| const typescriptPreprocessor = require('./typescriptPreprocessor'); | ||||
| 
 | ||||
| module.exports = (on, config) => { | ||||
|  | @ -10,7 +11,7 @@ module.exports = (on, config) => { | |||
|   //   failed: require('cypress-failed-log/src/failed')(),
 | ||||
|   // });
 | ||||
|   on('file:preprocessor', typescriptPreprocessor); | ||||
|   on('task', { compareSnapshotsPlugin }); | ||||
|   on('task', { compareSnapshotsPlugin, readProvisions }); | ||||
|   on('task', { | ||||
|     log({ message, optional }) { | ||||
|       optional ? console.log(message, optional) : console.log(message); | ||||
|  |  | |||
|  | @ -0,0 +1,14 @@ | |||
| 'use strict'; | ||||
| const { parse: parseYml } = require('yaml'); | ||||
| const { | ||||
|   promises: { readFile }, | ||||
| } = require('fs'); | ||||
| const { resolve: resolvePath } = require('path'); | ||||
| 
 | ||||
| const readProvision = filePath => readFile(filePath, 'utf8').then(contents => parseYml(contents)); | ||||
| 
 | ||||
| const readProvisions = filePaths => Promise.all(filePaths.map(readProvision)); | ||||
| 
 | ||||
| // Paths are relative to <project-root>/provisioning
 | ||||
| module.exports = ({ CWD, filePaths }) => | ||||
|   readProvisions(filePaths.map(filePath => resolvePath(CWD, 'provisioning', filePath))); | ||||
|  | @ -25,3 +25,10 @@ Cypress.Commands.add('compareSnapshot', (args: CompareSnapshotArgs) => { | |||
| Cypress.Commands.add('logToConsole', (message: string, optional?: any) => { | ||||
|   cy.task('log', { message, optional }); | ||||
| }); | ||||
| 
 | ||||
| Cypress.Commands.add('readProvisions', (filePaths: string[]) => { | ||||
|   cy.task('readProvisions', { | ||||
|     CWD: Cypress.env('CWD'), | ||||
|     filePaths, | ||||
|   }); | ||||
| }); | ||||
|  |  | |||
|  | @ -4,5 +4,6 @@ declare namespace Cypress { | |||
|   interface Chainable { | ||||
|     compareSnapshot(args: CompareSnapshotArgs): void; | ||||
|     logToConsole(message: string, optional?: any): void; | ||||
|     readProvisions(filePaths: string[]): Chainable; | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -55,6 +55,7 @@ | |||
|     "cypress": "3.7.0", | ||||
|     "execa": "4.0.0", | ||||
|     "ts-loader": "6.2.1", | ||||
|     "typescript": "3.7.2" | ||||
|     "typescript": "3.7.2", | ||||
|     "yaml": "^1.8.3" | ||||
|   } | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| import { e2e } from '../index'; | ||||
| import { Url } from '../support/url'; | ||||
| import { getDashboardUid } from '../support/url'; | ||||
| 
 | ||||
| export const addDashboard = () => { | ||||
|   e2e().logToConsole('Adding dashboard'); | ||||
|  | @ -11,7 +11,9 @@ export const addDashboard = () => { | |||
|   e2e() | ||||
|     .url() | ||||
|     .then((url: string) => { | ||||
|       e2e.context().set('lastAddedDashboard', dashboardTitle); | ||||
|       e2e.context().set('lastAddedDashboardUid', Url.getDashboardUid(url)); | ||||
|       e2e.setScenarioContext({ | ||||
|         lastAddedDashboard: dashboardTitle, | ||||
|         lastAddedDashboardUid: getDashboardUid(url), | ||||
|       }); | ||||
|     }); | ||||
| }; | ||||
|  |  | |||
|  | @ -1,22 +1,64 @@ | |||
| import { e2e } from '../index'; | ||||
| import { fromBaseUrl, getDataSourceId } from '../support/url'; | ||||
| import { setScenarioContext } from '../support/scenarioContext'; | ||||
| 
 | ||||
| export const addDataSource = (pluginName?: string): string => { | ||||
|   pluginName = pluginName || 'TestData DB'; | ||||
|   e2e().logToConsole('Adding data source with pluginName:', pluginName); | ||||
| export interface AddDataSourceConfig { | ||||
|   checkHealth: boolean; | ||||
|   expectedAlertMessage: string; | ||||
|   form: Function; | ||||
|   name: string; | ||||
| } | ||||
| 
 | ||||
| const DEFAULT_ADD_DATA_SOURCE_CONFIG: AddDataSourceConfig = { | ||||
|   checkHealth: false, | ||||
|   expectedAlertMessage: 'Data source is working', | ||||
|   form: () => {}, | ||||
|   name: 'TestData DB', | ||||
| }; | ||||
| 
 | ||||
| export const addDataSource = (config?: Partial<AddDataSourceConfig>): string => { | ||||
|   const { checkHealth, expectedAlertMessage, form, name } = { ...DEFAULT_ADD_DATA_SOURCE_CONFIG, ...config }; | ||||
| 
 | ||||
|   e2e().logToConsole('Adding data source with name:', name); | ||||
|   e2e.pages.AddDataSource.visit(); | ||||
|   e2e.pages.AddDataSource.dataSourcePlugins(pluginName) | ||||
|   e2e.pages.AddDataSource.dataSourcePlugins(name) | ||||
|     .scrollIntoView() | ||||
|     .should('be.visible') // prevents flakiness
 | ||||
|     .click(); | ||||
| 
 | ||||
|   const dataSourceName = `e2e-${new Date().getTime()}`; | ||||
|   const dataSourceName = `e2e-${Date.now()}`; | ||||
|   e2e.pages.DataSource.name().clear(); | ||||
|   e2e.pages.DataSource.name().type(dataSourceName); | ||||
|   form(); | ||||
|   e2e.pages.DataSource.saveAndTest().click(); | ||||
|   e2e.pages.DataSource.alert().should('exist'); | ||||
|   e2e.pages.DataSource.alertMessage().should('contain.text', 'Data source is working'); | ||||
|   e2e.pages.DataSource.alertMessage().should('contain.text', expectedAlertMessage); | ||||
|   e2e().logToConsole('Added data source with name:', dataSourceName); | ||||
|   e2e.context().set('lastAddedDataSource', dataSourceName); | ||||
| 
 | ||||
|   if (checkHealth) { | ||||
|     e2e() | ||||
|       .url() | ||||
|       .then((url: string) => { | ||||
|         const dataSourceId = getDataSourceId(url); | ||||
| 
 | ||||
|         setScenarioContext({ | ||||
|           lastAddedDataSource: dataSourceName, | ||||
|           lastAddedDataSourceId: dataSourceId, | ||||
|         }); | ||||
| 
 | ||||
|         const healthUrl = fromBaseUrl(`/api/datasources/${dataSourceId}/health`); | ||||
|         e2e().logToConsole(`Fetching ${healthUrl}`); | ||||
|         e2e() | ||||
|           .request(healthUrl) | ||||
|           .its('body') | ||||
|           .should('have.property', 'status') | ||||
|           .and('eq', 'OK'); | ||||
|       }); | ||||
|   } else { | ||||
|     setScenarioContext({ | ||||
|       lastAddedDataSource: dataSourceName, | ||||
|     }); | ||||
|   } | ||||
| 
 | ||||
|   return dataSourceName; | ||||
| }; | ||||
|  |  | |||
|  | @ -0,0 +1,30 @@ | |||
| import { e2e } from '../index'; | ||||
| import { getScenarioContext } from '../support/scenarioContext'; | ||||
| 
 | ||||
| export interface AddPanelConfig { | ||||
|   dataSourceName: string; | ||||
|   queriesForm: Function; | ||||
| } | ||||
| 
 | ||||
| const DEFAULT_ADD_PANEL_CONFIG: AddPanelConfig = { | ||||
|   dataSourceName: 'TestData DB', | ||||
|   queriesForm: () => {}, | ||||
| }; | ||||
| 
 | ||||
| export const addPanel = (config?: Partial<AddPanelConfig>) => { | ||||
|   const { dataSourceName, queriesForm } = { ...DEFAULT_ADD_PANEL_CONFIG, ...config }; | ||||
| 
 | ||||
|   // @todo remove `@ts-ignore` when possible
 | ||||
|   // @ts-ignore
 | ||||
|   getScenarioContext().then(({ lastAddedDashboardUid }) => { | ||||
|     e2e.flows.openDashboard(lastAddedDashboardUid); | ||||
|     e2e.pages.Dashboard.Toolbar.toolbarItems('Add panel').click(); | ||||
|     e2e.pages.AddDashboard.ctaButtons('Add Query').click(); | ||||
|     e2e() | ||||
|       .get('.ds-picker') | ||||
|       .click() | ||||
|       .contains(dataSourceName) | ||||
|       .click(); | ||||
|     queriesForm(); | ||||
|   }); | ||||
| }; | ||||
|  | @ -1,9 +1,9 @@ | |||
| import { Url } from '../support/url'; | ||||
| import { e2e } from '../index'; | ||||
| import { fromBaseUrl } from '../support/url'; | ||||
| 
 | ||||
| export const deleteDashboard = (dashBoardUid: string) => { | ||||
|   e2e().logToConsole('Deleting dashboard with uid:', dashBoardUid); | ||||
|   e2e().request('DELETE', Url.fromBaseUrl(`/api/dashboards/uid/${dashBoardUid}`)); | ||||
|   e2e().request('DELETE', fromBaseUrl(`/api/dashboards/uid/${dashBoardUid}`)); | ||||
| 
 | ||||
|   /* https://github.com/cypress-io/cypress/issues/2831 | ||||
|   Flows.openDashboard(dashboardName); | ||||
|  |  | |||
|  | @ -1,9 +1,9 @@ | |||
| import { Url } from '../support/url'; | ||||
| import { e2e } from '../index'; | ||||
| import { fromBaseUrl } from '../support/url'; | ||||
| 
 | ||||
| export const deleteDataSource = (dataSourceName: string) => { | ||||
|   e2e().logToConsole('Deleting data source with name:', dataSourceName); | ||||
|   e2e().request('DELETE', Url.fromBaseUrl(`/api/datasources/name/${dataSourceName}`)); | ||||
|   e2e().request('DELETE', fromBaseUrl(`/api/datasources/name/${dataSourceName}`)); | ||||
| 
 | ||||
|   /* https://github.com/cypress-io/cypress/issues/2831 | ||||
|   Pages.DataSources.visit(); | ||||
|  |  | |||
|  | @ -1,21 +1,23 @@ | |||
| import { login } from './login'; | ||||
| import { addDataSource } from './addDataSource'; | ||||
| import { deleteDataSource } from './deleteDataSource'; | ||||
| import { addDashboard } from './addDashboard'; | ||||
| import { addDataSource } from './addDataSource'; | ||||
| import { addPanel } from './addPanel'; | ||||
| import { assertSuccessNotification } from './assertSuccessNotification'; | ||||
| import { deleteDashboard } from './deleteDashboard'; | ||||
| import { deleteDataSource } from './deleteDataSource'; | ||||
| import { login } from './login'; | ||||
| import { openDashboard } from './openDashboard'; | ||||
| import { saveNewDashboard } from './saveNewDashboard'; | ||||
| import { saveDashboard } from './saveDashboard'; | ||||
| import { saveNewDashboard } from './saveNewDashboard'; | ||||
| 
 | ||||
| export const Flows = { | ||||
|   login, | ||||
|   addDataSource, | ||||
|   deleteDataSource, | ||||
|   addDashboard, | ||||
|   addDataSource, | ||||
|   addPanel, | ||||
|   assertSuccessNotification, | ||||
|   deleteDashboard, | ||||
|   deleteDataSource, | ||||
|   login, | ||||
|   openDashboard, | ||||
|   saveNewDashboard, | ||||
|   saveDashboard, | ||||
|   saveNewDashboard, | ||||
| }; | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ import { e2e } from '../index'; | |||
| export const saveNewDashboard = () => { | ||||
|   e2e.pages.Dashboard.Toolbar.toolbarItems('Save dashboard').click(); | ||||
| 
 | ||||
|   const dashboardTitle = `e2e-${new Date().getTime()}`; | ||||
|   const dashboardTitle = `e2e-${Date.now()}`; | ||||
|   e2e.pages.SaveDashboardAsModal.newName().clear(); | ||||
|   e2e.pages.SaveDashboardAsModal.newName().type(dashboardTitle); | ||||
|   e2e.pages.SaveDashboardAsModal.save().click(); | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ | |||
| import { e2eScenario, ScenarioArguments } from './support/scenario'; | ||||
| import { Pages } from './pages'; | ||||
| import { Flows } from './flows'; | ||||
| import { scenarioContext } from './support/scenarioContext'; | ||||
| import { getScenarioContext, setScenarioContext } from './support/scenarioContext'; | ||||
| 
 | ||||
| export type SelectorFunction = (text?: string) => Cypress.Chainable<JQuery<HTMLElement>>; | ||||
| export type SelectorObject<S> = { | ||||
|  | @ -20,9 +20,10 @@ const e2eObject = { | |||
|   blobToBase64String: (blob: any) => Cypress.Blob.blobToBase64String(blob), | ||||
|   imgSrcToBlob: (url: string) => Cypress.Blob.imgSrcToBlob(url), | ||||
|   scenario: (args: ScenarioArguments) => e2eScenario(args), | ||||
|   context: scenarioContext, | ||||
|   pages: Pages, | ||||
|   flows: Flows, | ||||
|   getScenarioContext, | ||||
|   setScenarioContext, | ||||
| }; | ||||
| 
 | ||||
| export const e2e: (() => Cypress.cy) & typeof e2eObject = Object.assign(() => cy, e2eObject); | ||||
|  |  | |||
|  | @ -3,7 +3,7 @@ import { e2e } from '../index'; | |||
| export interface ScenarioArguments { | ||||
|   describeName: string; | ||||
|   itName: string; | ||||
|   scenario: () => void; | ||||
|   scenario: Function; | ||||
|   skipScenario?: boolean; | ||||
|   addScenarioDataSource?: boolean; | ||||
|   addScenarioDashBoard?: boolean; | ||||
|  | @ -19,34 +19,33 @@ export const e2eScenario = ({ | |||
| }: ScenarioArguments) => { | ||||
|   describe(describeName, () => { | ||||
|     if (skipScenario) { | ||||
|       it.skip(itName, () => { | ||||
|         // @ts-ignore yarn start in root throws error otherwise
 | ||||
|         expect(false).equals(true); | ||||
|       it.skip(itName, () => scenario()); | ||||
|     } else { | ||||
|       beforeEach(() => { | ||||
|         e2e.flows.login('admin', 'admin'); | ||||
|         if (addScenarioDataSource) { | ||||
|           e2e.flows.addDataSource(); | ||||
|         } | ||||
|         if (addScenarioDashBoard) { | ||||
|           e2e.flows.addDashboard(); | ||||
|         } | ||||
|       }); | ||||
|       return; | ||||
| 
 | ||||
|       afterEach(() => { | ||||
|         // @todo remove `@ts-ignore` when possible
 | ||||
|         // @ts-ignore
 | ||||
|         e2e.getScenarioContext().then(({ lastAddedDashboardUid, lastAddedDataSource }) => { | ||||
|           if (lastAddedDataSource) { | ||||
|             e2e.flows.deleteDataSource(lastAddedDataSource); | ||||
|           } | ||||
| 
 | ||||
|           if (lastAddedDashboardUid) { | ||||
|             e2e.flows.deleteDashboard(lastAddedDashboardUid); | ||||
|           } | ||||
|         }); | ||||
|       }); | ||||
| 
 | ||||
|       it(itName, () => scenario()); | ||||
|     } | ||||
| 
 | ||||
|     beforeEach(() => { | ||||
|       e2e.flows.login('admin', 'admin'); | ||||
|       if (addScenarioDataSource) { | ||||
|         e2e.flows.addDataSource('TestData DB'); | ||||
|       } | ||||
|       if (addScenarioDashBoard) { | ||||
|         e2e.flows.addDashboard(); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     afterEach(() => { | ||||
|       if (e2e.context().get('lastAddedDataSource')) { | ||||
|         e2e.flows.deleteDataSource(e2e.context().get('lastAddedDataSource')); | ||||
|       } | ||||
|       if (e2e.context().get('lastAddedDashboardUid')) { | ||||
|         e2e.flows.deleteDashboard(e2e.context().get('lastAddedDashboardUid')); | ||||
|       } | ||||
|     }); | ||||
| 
 | ||||
|     it(itName, () => { | ||||
|       scenario(); | ||||
|     }); | ||||
|   }); | ||||
| }; | ||||
|  |  | |||
|  | @ -1,29 +1,36 @@ | |||
| import { e2e } from '../index'; | ||||
| 
 | ||||
| export interface ScenarioContext { | ||||
|   lastAddedDataSource: string; | ||||
|   lastAddedDashboard: string; | ||||
|   lastAddedDashboardUid: string; | ||||
|   lastAddedDataSource: string; | ||||
|   lastAddedDataSourceId: string; | ||||
|   [key: string]: any; | ||||
| } | ||||
| 
 | ||||
| const scenarioContexts: ScenarioContext = { | ||||
|   lastAddedDataSource: '', | ||||
| const scenarioContext: ScenarioContext = { | ||||
|   lastAddedDashboard: '', | ||||
|   lastAddedDashboardUid: '', | ||||
|   lastAddedDataSource: '', | ||||
|   lastAddedDataSourceId: '', | ||||
| }; | ||||
| 
 | ||||
| export interface ScenarioContextApi { | ||||
|   get: <T>(name: string | keyof ScenarioContext) => T; | ||||
|   set: <T>(name: string | keyof ScenarioContext, value: T) => void; | ||||
| } | ||||
| // @todo this actually returns type `Cypress.Chainable`
 | ||||
| export const getScenarioContext = (): any => | ||||
|   e2e() | ||||
|     .wrap({ | ||||
|       getScenarioContext: () => ({ ...scenarioContext } as ScenarioContext), | ||||
|     }) | ||||
|     .invoke('getScenarioContext'); | ||||
| 
 | ||||
| export const scenarioContext = (): ScenarioContextApi => { | ||||
|   const get = <T>(name: string | keyof ScenarioContext): T => scenarioContexts[name] as T; | ||||
|   const set = <T>(name: string | keyof ScenarioContext, value: T): void => { | ||||
|     scenarioContexts[name] = value; | ||||
|   }; | ||||
| 
 | ||||
|   return { | ||||
|     get, | ||||
|     set, | ||||
|   }; | ||||
| }; | ||||
| // @todo this actually returns type `Cypress.Chainable`
 | ||||
| export const setScenarioContext = (newContext: Partial<ScenarioContext>): any => | ||||
|   e2e() | ||||
|     .wrap({ | ||||
|       setScenarioContext: () => { | ||||
|         Object.entries(newContext).forEach(([key, value]) => { | ||||
|           scenarioContext[key] = value; | ||||
|         }); | ||||
|       }, | ||||
|     }) | ||||
|     .invoke('setScenarioContext'); | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| import { Selector } from './selector'; | ||||
| import { Url } from './url'; | ||||
| import { fromBaseUrl } from './url'; | ||||
| import { e2e } from '../index'; | ||||
| import { SelectorFunction, SelectorObject } from '../noTypeCheck'; | ||||
| 
 | ||||
|  | @ -19,11 +19,11 @@ export const pageFactory = <S extends Selectors>({ url, selectors }: PageFactory | |||
| 
 | ||||
|     let parsedUrl = ''; | ||||
|     if (typeof url === 'string') { | ||||
|       parsedUrl = Url.fromBaseUrl(url); | ||||
|       parsedUrl = fromBaseUrl(url); | ||||
|     } | ||||
| 
 | ||||
|     if (typeof url === 'function' && args) { | ||||
|       parsedUrl = Url.fromBaseUrl(url(args)); | ||||
|       parsedUrl = fromBaseUrl(url(args)); | ||||
|     } | ||||
| 
 | ||||
|     e2e().logToConsole('Visiting', parsedUrl); | ||||
|  |  | |||
|  | @ -1,25 +1,26 @@ | |||
| import { e2e } from '../index'; | ||||
| 
 | ||||
| export interface UrlApi { | ||||
|   fromBaseUrl: (url: string | undefined) => string; | ||||
|   getDashboardUid: (url: string) => string; | ||||
| } | ||||
| 
 | ||||
| const uidRegex = '\\/d\\/(.*)\\/'; | ||||
| const getBaseUrl = () => e2e.env('BASE_URL') || e2e.config().baseUrl || 'http://localhost:3000'; | ||||
| 
 | ||||
| export const Url: UrlApi = { | ||||
|   fromBaseUrl: (url: string | undefined) => { | ||||
|     url = url || ''; | ||||
|     const strippedUrl = url.replace('^/', ''); | ||||
|     return `${getBaseUrl()}${strippedUrl}`; | ||||
|   }, | ||||
|   getDashboardUid: (url: string) => { | ||||
|     const matches = url.match(uidRegex); | ||||
|     if (!matches) { | ||||
|       throw new Error(`Couldn't parse uid from ${url}`); | ||||
|     } | ||||
| 
 | ||||
|     return matches[1]; | ||||
|   }, | ||||
| export const fromBaseUrl = (url = ''): string => { | ||||
|   const strippedUrl = url.replace('^/', ''); | ||||
|   return `${getBaseUrl()}${strippedUrl}`; | ||||
| }; | ||||
| 
 | ||||
| export const getDashboardUid = (url: string): string => { | ||||
|   const matches = url.match(/\/d\/(.*)\//); | ||||
|   if (!matches) { | ||||
|     throw new Error(`Couldn't parse uid from ${url}`); | ||||
|   } else { | ||||
|     return matches[1]; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| export const getDataSourceId = (url: string): string => { | ||||
|   const matches = url.match(/\/edit\/(.*)\//); | ||||
|   if (!matches) { | ||||
|     throw new Error(`Couldn't parse id from ${url}`); | ||||
|   } else { | ||||
|     return matches[1]; | ||||
|   } | ||||
| }; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue