Chore: remove wrapping of cy in the e2e object (#74650)

* remove cy. wrapping as e2e().

* make trace-view-scrolling more stable and remove waits

* improve stability more
This commit is contained in:
Ashley Harrison
2023-09-11 11:20:54 +01:00
committed by GitHub
parent 7718a67b77
commit 247d91be2b
54 changed files with 518 additions and 622 deletions
+5 -5
View File
@@ -125,7 +125,7 @@ export const addDashboard = (config?: Partial<AddDashboardConfig>) => {
const { annotations, timeRange, title, variables } = fullConfig;
e2e().logToConsole('Adding dashboard with title:', title);
cy.logToConsole('Adding dashboard with title:', title);
e2e.pages.AddDashboard.visit();
@@ -146,9 +146,9 @@ export const addDashboard = (config?: Partial<AddDashboardConfig>) => {
e2e.flows.assertSuccessNotification();
e2e.pages.AddDashboard.itemButton('Create new panel button').should('be.visible');
e2e().logToConsole('Added dashboard with title:', title);
cy.logToConsole('Added dashboard with title:', title);
return e2e()
return cy
.url()
.should('contain', '/d/')
.then((url: string) => {
@@ -161,7 +161,7 @@ export const addDashboard = (config?: Partial<AddDashboardConfig>) => {
});
// @todo remove `wrap` when possible
return e2e().wrap(
return cy.wrap(
{
config: fullConfig,
uid,
@@ -278,7 +278,7 @@ const addVariable = (config: PartialAddVariableConfig, isFirst: boolean): AddVar
}
// Avoid flakiness
e2e().focused().blur();
cy.focused().blur();
e2e.pages.Dashboard.Settings.Variables.Edit.General.previewOfValuesOption()
.should('exist')
+22 -27
View File
@@ -45,12 +45,10 @@ export const addDataSource = (config?: Partial<AddDataSourceConfig>) => {
} = fullConfig;
if (awaitHealth) {
e2e()
.intercept(/health/)
.as('health');
cy.intercept(/health/).as('health');
}
e2e().logToConsole('Adding data source with name:', name);
cy.logToConsole('Adding data source with name:', name);
e2e.pages.AddDataSource.visit();
e2e.pages.AddDataSource.dataSourcePluginsV2(type)
.scrollIntoView()
@@ -61,23 +59,22 @@ export const addDataSource = (config?: Partial<AddDataSourceConfig>) => {
e2e.pages.DataSource.name().type(name);
if (basicAuth) {
e2e().contains('label', 'Basic auth').scrollIntoView().click();
e2e()
.contains('.gf-form-group', 'Basic Auth Details')
cy.contains('label', 'Basic auth').scrollIntoView().click();
cy.contains('.gf-form-group', 'Basic Auth Details')
.should('be.visible')
.scrollIntoView()
.within(() => {
if (basicAuthUser) {
e2e().get('[placeholder=user]').type(basicAuthUser);
cy.get('[placeholder=user]').type(basicAuthUser);
}
if (basicAuthPassword) {
e2e().get('[placeholder=Password]').type(basicAuthPassword);
cy.get('[placeholder=Password]').type(basicAuthPassword);
}
});
}
if (skipTlsVerify) {
e2e().contains('label', 'Skip TLS Verify').scrollIntoView().click();
cy.contains('label', 'Skip TLS Verify').scrollIntoView().click();
}
form();
@@ -85,7 +82,7 @@ export const addDataSource = (config?: Partial<AddDataSourceConfig>) => {
e2e.pages.DataSource.saveAndTest().click();
if (awaitHealth) {
e2e().wait('@health', { timeout: timeout ?? e2e.config().defaultCommandTimeout });
cy.wait('@health', { timeout: timeout ?? e2e.config().defaultCommandTimeout });
}
// use the timeout passed in if it exists, otherwise, continue to use the default
@@ -94,23 +91,21 @@ export const addDataSource = (config?: Partial<AddDataSourceConfig>) => {
.contains(expectedAlertMessage, {
timeout: timeout ?? e2e.config().defaultCommandTimeout,
});
e2e().logToConsole('Added data source with name:', name);
cy.logToConsole('Added data source with name:', name);
return e2e()
.url()
.then(() => {
e2e.getScenarioContext().then(({ addedDataSources }: any) => {
e2e.setScenarioContext({
addedDataSources: [...addedDataSources, { name } as DeleteDataSourceConfig],
});
return cy.url().then(() => {
e2e.getScenarioContext().then(({ addedDataSources }: any) => {
e2e.setScenarioContext({
addedDataSources: [...addedDataSources, { name } as DeleteDataSourceConfig],
});
// @todo remove `wrap` when possible
return e2e().wrap(
{
config: fullConfig,
},
{ log: false }
);
});
// @todo remove `wrap` when possible
return cy.wrap(
{
config: fullConfig,
},
{ log: false }
);
});
};
+9 -9
View File
@@ -109,14 +109,14 @@ export const configurePanel = (config: PartialAddPanelConfig | PartialEditPanelC
// @todo alias '/**/*.js*' as '@pluginModule' when possible: https://github.com/cypress-io/cypress/issues/1296
e2e().intercept(chartData.method, chartData.route).as('chartData');
cy.intercept(chartData.method, chartData.route).as('chartData');
if (dataSourceName) {
e2e.components.DataSourcePicker.container().click().type(`${dataSourceName}{downArrow}{enter}`);
}
// @todo instead wait for '@pluginModule' if not already loaded
e2e().wait(2000);
cy.wait(2000);
// `panelTitle` is needed to edit the panel, and unlikely to have its value changed at that point
const changeTitle = panelTitle && !isEdit;
@@ -130,7 +130,7 @@ export const configurePanel = (config: PartialAddPanelConfig | PartialEditPanelC
e2e.components.PluginVisualization.item(visualizationName).scrollIntoView().click();
// @todo wait for '@pluginModule' if not a core visualization and not already loaded
e2e().wait(2000);
cy.wait(2000);
}
} else {
// Consistently closed
@@ -142,21 +142,21 @@ export const configurePanel = (config: PartialAddPanelConfig | PartialEditPanelC
// Wait for a possible complex visualization to render (or something related, as this isn't necessary on the dashboard page)
// Can't assert that its HTML changed because a new query could produce the same results
e2e().wait(1000);
cy.wait(1000);
}
// @todo enable when plugins have this implemented
//e2e.components.QueryEditorRow.actionButton('Disable/enable query').click();
//e2e().wait('@chartData');
//cy.wait('@chartData');
//e2e.components.Panels.Panel.containerByTitle(panelTitle).find('.panel-content').contains('No data');
//e2e.components.QueryEditorRow.actionButton('Disable/enable query').click();
//e2e().wait('@chartData');
//cy.wait('@chartData');
// Avoid annotations flakiness
e2e.components.RefreshPicker.runButtonV2().first().click({ force: true });
// Wait for RxJS
e2e().wait(timeout ?? e2e.config().defaultCommandTimeout);
cy.wait(timeout ?? e2e.config().defaultCommandTimeout);
if (matchScreenshot) {
let visualization;
@@ -164,11 +164,11 @@ export const configurePanel = (config: PartialAddPanelConfig | PartialEditPanelC
visualization = e2e.components.Panels.Panel.containerByTitle(panelTitle).find('.panel-content');
visualization.scrollIntoView().screenshot(screenshotName);
e2e().compareScreenshots(screenshotName);
cy.compareScreenshots(screenshotName);
}
// @todo remove `wrap` when possible
return e2e().wrap({ config: fullConfig }, { log: false });
return cy.wrap({ config: fullConfig }, { log: false });
});
// @todo this actually returns type `Cypress.Chainable`
+5 -7
View File
@@ -8,7 +8,7 @@ export interface DeleteDashboardConfig {
}
export const deleteDashboard = ({ quick = false, title, uid }: DeleteDashboardConfig) => {
e2e().logToConsole('Deleting dashboard with uid:', uid);
cy.logToConsole('Deleting dashboard with uid:', uid);
if (quick) {
quickDelete(uid);
@@ -16,7 +16,7 @@ export const deleteDashboard = ({ quick = false, title, uid }: DeleteDashboardCo
uiDelete(uid, title);
}
e2e().logToConsole('Deleted dashboard with uid:', uid);
cy.logToConsole('Deleted dashboard with uid:', uid);
e2e.getScenarioContext().then(({ addedDashboards }: any) => {
e2e.setScenarioContext({
@@ -28,7 +28,7 @@ export const deleteDashboard = ({ quick = false, title, uid }: DeleteDashboardCo
};
const quickDelete = (uid: string) => {
e2e().request('DELETE', fromBaseUrl(`/api/dashboards/uid/${uid}`));
cy.request('DELETE', fromBaseUrl(`/api/dashboards/uid/${uid}`));
};
const uiDelete = (uid: string, title: string) => {
@@ -42,10 +42,8 @@ const uiDelete = (uid: string, title: string) => {
// @todo replace `e2e.pages.Dashboards.dashboards` with this when argument is empty
if (e2e.components.Search.dashboardItems) {
e2e.components.Search.dashboardItems().each((item) => e2e().wrap(item).should('not.contain', title));
e2e.components.Search.dashboardItems().each((item) => cy.wrap(item).should('not.contain', title));
} else {
e2e()
.get('[aria-label^="Dashboard search item "]')
.each((item) => e2e().wrap(item).should('not.contain', title));
cy.get('[aria-label^="Dashboard search item "]').each((item) => cy.wrap(item).should('not.contain', title));
}
};
+4 -6
View File
@@ -8,7 +8,7 @@ export interface DeleteDataSourceConfig {
}
export const deleteDataSource = ({ id, name, quick = false }: DeleteDataSourceConfig) => {
e2e().logToConsole('Deleting data source with name:', name);
cy.logToConsole('Deleting data source with name:', name);
if (quick) {
quickDelete(name);
@@ -16,7 +16,7 @@ export const deleteDataSource = ({ id, name, quick = false }: DeleteDataSourceCo
uiDelete(name);
}
e2e().logToConsole('Deleted data source with name:', name);
cy.logToConsole('Deleted data source with name:', name);
e2e.getScenarioContext().then(({ addedDataSources }: any) => {
e2e.setScenarioContext({
@@ -28,7 +28,7 @@ export const deleteDataSource = ({ id, name, quick = false }: DeleteDataSourceCo
};
const quickDelete = (name: string) => {
e2e().request('DELETE', fromBaseUrl(`/api/datasources/name/${name}`));
cy.request('DELETE', fromBaseUrl(`/api/datasources/name/${name}`));
};
const uiDelete = (name: string) => {
@@ -40,7 +40,5 @@ const uiDelete = (name: string) => {
e2e.pages.DataSources.visit();
// @todo replace `e2e.pages.DataSources.dataSources` with this when argument is empty
e2e()
.get('[aria-label^="Data source list item "]')
.each((item) => e2e().wrap(item).should('not.contain', name));
cy.get('[aria-label^="Data source list item "]').each((item) => cy.wrap(item).should('not.contain', name));
};
+3 -4
View File
@@ -17,7 +17,7 @@ export type Dashboard = { title: string; panels: Panel[]; uid: string; [key: str
* @param skipPanelValidation skip panel validation
*/
export const importDashboard = (dashboardToImport: Dashboard, queryTimeout?: number, skipPanelValidation?: boolean) => {
e2e().visit(fromBaseUrl('/dashboard/import'));
cy.visit(fromBaseUrl('/dashboard/import'));
// Note: normally we'd use 'click' and then 'type' here, but the json object is so big that using 'val' is much faster
e2e.components.DashboardImportPage.textarea().should('be.visible');
@@ -28,11 +28,10 @@ export const importDashboard = (dashboardToImport: Dashboard, queryTimeout?: num
e2e.components.ImportDashboardForm.submit().should('be.visible').click();
// wait for dashboard to load
e2e().wait(queryTimeout || 6000);
cy.wait(queryTimeout || 6000);
// save the newly imported dashboard to context so it'll get properly deleted later
e2e()
.url()
cy.url()
.should('contain', '/d/')
.then((url: string) => {
const uid = getDashboardUid(url);
+4 -6
View File
@@ -11,11 +11,9 @@ import { importDashboard, Dashboard } from './importDashboard';
* @param skipPanelValidation skips panel validation
*/
export const importDashboards = async (dirPath: string, queryTimeout?: number, skipPanelValidation?: boolean) => {
e2e()
.getJSONFilesFromDir(dirPath)
.then((jsonFiles: Dashboard[]) => {
jsonFiles.forEach((file) => {
importDashboard(file, queryTimeout || 6000, skipPanelValidation);
});
cy.getJSONFilesFromDir(dirPath).then((jsonFiles: Dashboard[]) => {
jsonFiles.forEach((file) => {
importDashboard(file, queryTimeout || 6000, skipPanelValidation);
});
});
};
+3 -3
View File
@@ -16,7 +16,7 @@ const loginApi = (username: string, password: string) => {
};
const loginUi = (username: string, password: string) => {
e2e().logToConsole('Logging in with username:', username);
cy.logToConsole('Logging in with username:', username);
e2e.pages.Login.visit();
e2e.pages.Login.username()
.should('be.visible') // prevents flakiness
@@ -29,7 +29,7 @@ const loginUi = (username: string, password: string) => {
e2e.pages.Login.skip().should('be.visible').click();
}
e2e().get('.login-page').should('not.exist');
cy.get('.login-page').should('not.exist');
};
export const login = (username = DEFAULT_USERNAME, password = DEFAULT_PASSWORD, loginViaApi = true) => {
@@ -38,5 +38,5 @@ export const login = (username = DEFAULT_USERNAME, password = DEFAULT_PASSWORD,
} else {
loginUi(username, password);
}
e2e().logToConsole('Logged in with username:', username);
cy.logToConsole('Logged in with username:', username);
};
+1 -1
View File
@@ -32,5 +32,5 @@ export const openDashboard = (config?: PartialOpenDashboardConfig) =>
}
// @todo remove `wrap` when possible
return e2e().wrap({ config: fullConfig }, { log: false });
return cy.wrap({ config: fullConfig }, { log: false });
});
+4 -6
View File
@@ -19,12 +19,10 @@ export const selectOption = (config: SelectOptionConfig): any => {
container.within(() => {
if (clickToOpen) {
e2e()
.get('[class$="-input-suffix"]', { timeout: 1000 })
.then((element) => {
expect(Cypress.dom.isAttached(element)).to.eq(true);
e2e().get('[class$="-input-suffix"]', { timeout: 1000 }).click({ force: true });
});
cy.get('[class$="-input-suffix"]', { timeout: 1000 }).then((element) => {
expect(Cypress.dom.isAttached(element)).to.eq(true);
cy.get('[class$="-input-suffix"]', { timeout: 1000 }).click({ force: true });
});
}
});
+2 -2
View File
@@ -12,8 +12,8 @@ export const setTimeRange = ({ from, to, zone }: TimeRangeConfig) => {
e2e.components.TimePicker.openButton().click();
if (zone) {
e2e().contains('button', 'Change time settings').click();
e2e().log('setting time zone to ' + zone);
cy.contains('button', 'Change time settings').click();
cy.log('setting time zone to ' + zone);
if (e2e.components.TimeZonePicker.containerV2) {
selectOption({
+1 -3
View File
@@ -7,7 +7,7 @@ import { e2eScenario, ScenarioArguments } from './support/scenario';
import { getScenarioContext, setScenarioContext } from './support/scenarioContext';
import * as typings from './typings';
const e2eObject = {
export const e2e = {
env: (args: string) => Cypress.env(args),
config: () => Cypress.config(),
blobToBase64String: (blob: Blob) => Cypress.Blob.blobToBase64String(blob),
@@ -22,5 +22,3 @@ const e2eObject = {
setScenarioContext,
getSelectors: <T extends Selectors>(selectors: E2ESelectors<T>) => e2eFactory({ selectors }),
};
export const e2e: (() => Cypress.cy) & typeof e2eObject = Object.assign(() => cy, e2eObject);
+10 -14
View File
@@ -49,28 +49,24 @@ export const benchmark = ({
return it(testName, () => {
e2e.flows.openDashboard();
e2e().wait(dashboard.delayAfterOpening);
cy.wait(dashboard.delayAfterOpening);
if (appStats) {
const startCollecting = appStats.startCollecting;
if (startCollecting) {
e2e()
.window()
.then((win) => startCollecting(win));
cy.window().then((win) => startCollecting(win));
}
e2e().startBenchmarking(testName);
e2e().wait(duration);
cy.startBenchmarking(testName);
cy.wait(duration);
e2e()
.window()
.then((win) => {
e2e().stopBenchmarking(testName, appStats.collect(win));
});
cy.window().then((win) => {
cy.stopBenchmarking(testName, appStats.collect(win));
});
} else {
e2e().startBenchmarking(testName);
e2e().wait(duration);
e2e().stopBenchmarking(testName, {});
cy.startBenchmarking(testName);
cy.wait(duration);
cy.stopBenchmarking(testName, {});
}
});
});
+1 -3
View File
@@ -2,9 +2,7 @@ import { e2e } from '../index';
// @todo this actually returns type `Cypress.Chainable`
const get = (key: string): any =>
e2e()
.wrap({ getLocalStorage: () => localStorage.getItem(key) }, { log: false })
.invoke('getLocalStorage');
cy.wrap({ getLocalStorage: () => localStorage.getItem(key) }, { log: false }).invoke('getLocalStorage');
// @todo this actually returns type `Cypress.Chainable`
export const getLocalStorage = (key: string): any =>
+2 -2
View File
@@ -37,7 +37,7 @@ const lastProperty = <T extends DeleteDashboardConfig | DeleteDataSourceConfig,
) => items[items.length - 1]?.[key] ?? '';
export const getScenarioContext = (): Cypress.Chainable<ScenarioContext> =>
e2e()
cy
.wrap(
{
getScenarioContext: (): ScenarioContext => ({ ...scenarioContext }),
@@ -47,7 +47,7 @@ export const getScenarioContext = (): Cypress.Chainable<ScenarioContext> =>
.invoke({ log: false }, 'getScenarioContext');
export const setScenarioContext = (newContext: Partial<ScenarioContext>): Cypress.Chainable<ScenarioContext> =>
e2e()
cy
.wrap(
{
setScenarioContext: () => {
+9 -11
View File
@@ -1,7 +1,5 @@
import { CssSelector, FunctionSelector, Selectors, StringSelector, UrlSelector } from '@grafana/e2e-selectors';
import { e2e } from '../index';
import { Selector } from './selector';
import { fromBaseUrl } from './url';
@@ -34,7 +32,7 @@ export type E2EFactoryArgs<S extends Selectors> = { selectors: S };
export type CypressOptions = Partial<Cypress.Loggable & Cypress.Timeoutable & Cypress.Withinable & Cypress.Shadow>;
const processSelectors = <S extends Selectors>(e2eObjects: E2EFunctions<S>, selectors: S): E2EFunctions<S> => {
const logOutput = (data: any) => e2e().logToConsole('Retrieving Selector:', data);
const logOutput = (data: any) => cy.logToConsole('Retrieving Selector:', data);
const keys = Object.keys(selectors);
for (let index = 0; index < keys.length; index++) {
const key = keys[index];
@@ -52,11 +50,11 @@ const processSelectors = <S extends Selectors>(e2eObjects: E2EFunctions<S>, sele
parsedUrl = fromBaseUrl(value(args));
}
e2e().logToConsole('Visiting', parsedUrl);
cy.logToConsole('Visiting', parsedUrl);
if (queryParams) {
return e2e().visit({ url: parsedUrl, qs: queryParams });
return cy.visit({ url: parsedUrl, qs: queryParams });
} else {
return e2e().visit(parsedUrl);
return cy.visit(parsedUrl);
}
};
@@ -71,7 +69,7 @@ const processSelectors = <S extends Selectors>(e2eObjects: E2EFunctions<S>, sele
? Selector.fromDataTestId(value)
: Selector.fromAriaLabel(value);
return e2e().get(selector, options);
return cy.get(selector, options);
};
continue;
@@ -85,7 +83,7 @@ const processSelectors = <S extends Selectors>(e2eObjects: E2EFunctions<S>, sele
const selector = value(undefined as unknown as string);
logOutput(selector);
return e2e().get(selector);
return cy.get(selector);
}
// the input can be (text) or (options)
@@ -97,12 +95,12 @@ const processSelectors = <S extends Selectors>(e2eObjects: E2EFunctions<S>, sele
: Selector.fromAriaLabel(selectorText);
logOutput(selector);
return e2e().get(selector);
return cy.get(selector);
}
const selector = value(undefined as unknown as string);
logOutput(selector);
return e2e().get(selector, textOrOptions);
return cy.get(selector, textOrOptions);
}
// the input can only be (text, options)
@@ -114,7 +112,7 @@ const processSelectors = <S extends Selectors>(e2eObjects: E2EFunctions<S>, sele
: Selector.fromAriaLabel(selectorText);
logOutput(selector);
return e2e().get(selector, options);
return cy.get(selector, options);
}
};