-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Plugin E2E: Make it possible to test data source config page #546
Changes from all commits
859a0a3
687199a
5d31e11
319fd0b
b77a09c
cd64c0c
25a4435
956c096
6c43320
da0e947
0f1bbee
1a6372c
767a21c
46cf727
f63a9c4
5d5343f
dd3f58a
21f6cb8
23d8c8a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"cookies": [], | ||
"origins": [] | ||
} |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
GOOGLE_JWT_FILE= | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. secret added to the repo. can also be found in plugin-provisioning repo if you want to try this locally (or provide your own ofc). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { v4 as uuidv4 } from 'uuid'; | ||
import { APIRequestContext, expect, TestFixture } from '@playwright/test'; | ||
import { PluginFixture, PluginOptions } from '../../api'; | ||
import { CreateDataSourceArgs, DataSource } from '../../types'; | ||
import { PlaywrightCombinedArgs } from '../types'; | ||
|
||
type CreateDataSourceViaAPIFixture = TestFixture< | ||
(args: CreateDataSourceArgs) => Promise<DataSource>, | ||
PluginFixture & PluginOptions & PlaywrightCombinedArgs | ||
>; | ||
|
||
export const createDataSourceViaAPI = async ( | ||
request: APIRequestContext, | ||
datasource: DataSource | ||
): Promise<DataSource> => { | ||
const { type, name } = datasource; | ||
const dsName = name ?? `${type}-${uuidv4()}`; | ||
|
||
const existingDataSource = await request.get(`/api/datasources/name/${dsName}`); | ||
if (await existingDataSource.ok()) { | ||
const json = await existingDataSource.json(); | ||
await request.delete(`/api/datasources/uid/${json.uid}`); | ||
} | ||
|
||
const createDsReq = await request.post('/api/datasources', { | ||
data: { | ||
...datasource, | ||
name: dsName, | ||
access: 'proxy', | ||
isDefault: false, | ||
}, | ||
}); | ||
const text = await createDsReq.text(); | ||
const status = await createDsReq.status(); | ||
if (status === 200) { | ||
console.log('Data source created: ', name); | ||
return createDsReq.json().then((r) => r.datasource); | ||
} | ||
|
||
expect.soft(createDsReq.ok(), `Failed to create data source: ${text}`).toBeTruthy(); | ||
return existingDataSource.json(); | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The code here is pretty rough and probably doesn't cover all scenarios...will probably come back to this in upcoming PRs. |
||
|
||
const createDataSource: CreateDataSourceViaAPIFixture = async ({ request }, use) => { | ||
await use(async (args) => { | ||
return createDataSourceViaAPI(request, args.datasource); | ||
}); | ||
}; | ||
|
||
export default createDataSource; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { expect, TestFixture } from '@playwright/test'; | ||
import { PluginFixture, PluginOptions } from '../../api'; | ||
import { CreateDataSourcePageArgs } from '../../types'; | ||
import { PlaywrightCombinedArgs } from '../types'; | ||
import { DataSourceConfigPage } from '../../models'; | ||
import { createDataSourceViaAPI } from './createDataSource'; | ||
|
||
type CreateDataSourceConfigPageFixture = TestFixture< | ||
(args: CreateDataSourcePageArgs) => Promise<DataSourceConfigPage>, | ||
PluginFixture & PluginOptions & PlaywrightCombinedArgs | ||
>; | ||
|
||
const createDataSourceConfigPage: CreateDataSourceConfigPageFixture = async ( | ||
{ request, page, selectors, grafanaVersion }, | ||
use | ||
) => { | ||
let datasourceConfigPage: DataSourceConfigPage | undefined; | ||
let deleteDataSource = true; | ||
await use(async (args) => { | ||
deleteDataSource = args.deleteDataSourceAfterTest ?? true; | ||
const datasource = await createDataSourceViaAPI(request, args); | ||
datasourceConfigPage = new DataSourceConfigPage( | ||
{ page, selectors, grafanaVersion, request }, | ||
expect, | ||
datasource.uid | ||
); | ||
await datasourceConfigPage.goto(); | ||
return datasourceConfigPage; | ||
}); | ||
deleteDataSource && datasourceConfigPage?.deleteDataSource(); | ||
}; | ||
|
||
export default createDataSourceConfigPage; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import path from 'path'; | ||
import { expect, TestFixture } from '@playwright/test'; | ||
import { PluginFixture, PluginOptions } from '../../api'; | ||
import { PlaywrightCombinedArgs } from '../types'; | ||
|
||
const authFile = 'playwright/.auth/user.json'; | ||
|
||
type LoginFixture = TestFixture<() => Promise<void>, PluginFixture & PluginOptions & PlaywrightCombinedArgs>; | ||
|
||
const login: LoginFixture = async ({ request, httpCredentials }, use) => { | ||
await use(async () => { | ||
const data = httpCredentials ? { ...httpCredentials, user: 'admin' } : { user: 'admin', password: 'admin' }; | ||
const loginReq = await request.post('/login', { data }); | ||
const text = await loginReq.text(); | ||
expect.soft(loginReq.ok(), `Could not log in to Grafana: ${text}`).toBeTruthy(); | ||
await request.storageState({ path: path.join(process.cwd(), authFile) }); | ||
}); | ||
}; | ||
|
||
export default login; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,11 @@ | ||
import grafanaVersion from './grafanaVersion'; | ||
import selectors from './selectors'; | ||
import login from './commands/login'; | ||
import createDataSourceConfigPage from './commands/createDataSourceConfigPage'; | ||
|
||
export default { | ||
selectors, | ||
grafanaVersion, | ||
login, | ||
createDataSourceConfigPage, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import toBeOK from './toBeOK'; | ||
|
||
export default { | ||
toBeOK, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { Response } from '@playwright/test'; | ||
import { getMessage } from './utils'; | ||
|
||
const toBeOK = async (request: Promise<Response>) => { | ||
let pass = false; | ||
let actual; | ||
let message: any = 'Response status code is within 200..299 range.'; | ||
|
||
try { | ||
const response = await request; | ||
return { | ||
message: () => getMessage(message, response.status().toString()), | ||
pass: response.ok(), | ||
actual: response.status(), | ||
}; | ||
} catch (err: unknown) { | ||
return { | ||
message: () => getMessage(message, err instanceof Error ? err.toString() : 'Unknown error'), | ||
pass, | ||
actual, | ||
}; | ||
} | ||
}; | ||
|
||
export default toBeOK; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export const getMessage = (expected: string, received: string) => `Expected: ${expected}\nReceived: ${received}`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { Expect } from '@playwright/test'; | ||
import { PluginTestCtx } from '../types'; | ||
import { GrafanaPage } from './GrafanaPage'; | ||
|
||
export class DataSourceConfigPage extends GrafanaPage { | ||
constructor(ctx: PluginTestCtx, expect: Expect<any>, private uid: string) { | ||
super(ctx, expect); | ||
} | ||
|
||
async deleteDataSource() { | ||
await this.ctx.request.delete(`/api/datasources/uid/${this.uid}`); | ||
} | ||
|
||
async goto() { | ||
await this.ctx.page.goto(this.ctx.selectors.pages.EditDataSource.url(this.uid), { | ||
waitUntil: 'load', | ||
}); | ||
} | ||
|
||
/** | ||
* Mocks the response of the datasource health check call | ||
* @param json the json response to return | ||
* @param status the HTTP status code to return. Defaults to 200 | ||
*/ | ||
async mockHealthCheckResponse<T = any>(json: T, status = 200) { | ||
await this.ctx.page.route(`${this.ctx.selectors.apis.DataSource.healthCheck}`, async (route) => { | ||
await route.fulfill({ json, status }); | ||
}); | ||
} | ||
|
||
async saveAndTest() { | ||
await this.getByTestIdOrAriaLabel(this.ctx.selectors.pages.DataSource.saveAndTest).click(); | ||
return this.ctx.page.waitForResponse((resp) => resp.url().includes('/health')); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wish playwright could create this file if it doesn't already exist, but doesn't seem like it's possible.