Skip to content
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

Create cypress command namespacing util #9150

Merged
merged 40 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
d3b7ecf
create namespaced osd utils
d-buckner Jan 6, 2025
97c20af
migrate 2 commands to osd utils for reference
d-buckner Jan 6, 2025
d9b55a2
Merge branch 'opensearch-project:main' into cy-utils-namespace
d-buckner Jan 6, 2025
cb73af9
Changeset file for PR #9150 created/updated
opensearch-changeset-bot[bot] Jan 6, 2025
ef48b11
Merge branch 'main' into cy-utils-namespace
d-buckner Jan 6, 2025
709b47c
address missed migrations
d-buckner Jan 6, 2025
2bd283c
simplify interface
d-buckner Jan 8, 2025
f6e8344
Changeset file for PR #9150 created/updated
opensearch-changeset-bot[bot] Jan 8, 2025
92a28e5
migrate missed util usage
d-buckner Jan 9, 2025
b6f75fe
add ts declaration and comments
d-buckner Jan 10, 2025
f10a696
remove unnecessary template literals
d-buckner Jan 14, 2025
efae3d3
fix: 0 rendered in discover when there are no results (#9153)
d-buckner Jan 8, 2025
0fcc69c
Update data source details to use small buttons (#9057)
ritvibhatt Jan 8, 2025
3f1d1ca
[Workspace] Add privacy levels to the workspace (#8907)
Kapian1234 Jan 8, 2025
f456a19
[workspace] refactor: refactor the bulk_get handler in permission wra…
Qxisylolo Jan 8, 2025
dd4fd71
[Auto Suggest] DQL Parsing updates and Fixes (#8931)
paulstn Jan 8, 2025
1e4951a
[workspace]add 2 step loading in 'Associate data sources' modal (#8999)
Qxisylolo Jan 9, 2025
8778f53
[Enhancement] Use HTTP service instead of fetch for plugin check (#9052)
RyanL1997 Jan 9, 2025
8b3fc16
[Workspace] Support to dissociate data connection object since DSM li…
raintygao Jan 9, 2025
c087420
Fix Unhandled Error Response of dev tool with MDS (#9159)
zhongnansu Jan 9, 2025
c31c843
Add a learn more flyout to the collaborators page (#9145)
Kapian1234 Jan 10, 2025
96dd558
[Workspace] Fix UI issues in workspace detail and create page (#8737)
Kapian1234 Jan 13, 2025
c211e09
Fix the display and jump logic for recent assets (#8136)
Kapian1234 Jan 13, 2025
473fb7d
[Cypress][Fix] Update saved search utilities (#9151)
angle943 Jan 13, 2025
1a6dede
chore: Update oui to 1.19 (#9172)
virajsanghvi Jan 13, 2025
fcd04ad
chore: use relative paths in cypress (#9079)
d-buckner Jan 13, 2025
8fc0c6e
Update text in workspace collaborators text box (#9181)
Naarcha-AWS Jan 15, 2025
c6adb0f
[workspace] fix set as default error in data source and index pattern…
Qxisylolo Jan 16, 2025
4b25e62
[Discover 2.0 Testing] Create View List of Saved Queries Test (Test-I…
ArgusLi Jan 16, 2025
7514024
change casing to folder structures to be compliant with our rules (#9…
angle943 Jan 16, 2025
2390c83
[Workspace]Dismiss get started for search/essential/analytics overvie…
Hailong-am Jan 17, 2025
10b8230
[Workspace] update workspace not found message to generic message (#9…
Hailong-am Jan 17, 2025
0a3791d
[Workspace] Address UI issues of index patterns (#8287)
Kapian1234 Jan 17, 2025
143d31c
Add data2summary check in data summary panel in discover (#8716)
Qxisylolo Jan 17, 2025
bf80d42
[Fix] Saved Search Integ Test Update: update saving a new saved searc…
angle943 Jan 17, 2025
cee4426
migrate 2 commands to osd utils for reference
d-buckner Jan 6, 2025
82bba68
address missed migrations
d-buckner Jan 6, 2025
dd946dc
Merge branch 'main' into cy-utils-namespace
d-buckner Jan 17, 2025
4e9cbf7
Merge branch 'main' into cy-utils-namespace
d-buckner Jan 17, 2025
ace9d48
Merge branch 'main' into cy-utils-namespace
ananzh Jan 19, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/9150.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
chore:
- Create cypress command namespacing util ([#9150](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/9150))
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ describe('No Index Pattern Check Test', () => {
authType: 'no_auth',
});
// Create workspace
cy.deleteWorkspaceByName(`${workspace}`);
cy.deleteWorkspaceByName(workspace);
cy.visit('/app/home');
cy.createInitialWorkspaceWithDataSource(`${DATASOURCE_NAME}`, `${workspace}`);
cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspace);
cy.wait(2000);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ describe('dataset selector', { scrollBehavior: false }, () => {
});
beforeEach(() => {
// Create workspace
cy.deleteWorkspaceByName(`${workspace}`);
cy.deleteWorkspaceByName(workspace);
cy.visit('/app/home');
cy.createInitialWorkspaceWithDataSource(`${DATASOURCE_NAME}`, `${workspace}`);
cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspace);
cy.navigateToWorkSpaceSpecificPage({
workspaceName: workspace,
page: 'discover',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('filter for value spec', () => {
// Create workspace
cy.deleteWorkspaceByName(workspace);
cy.visit('/app/home');
cy.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspace);
cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspace);
cy.wait(2000);
cy.createWorkspaceIndexPatterns({
workspaceName: workspace,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ describe('query enhancement queries', { scrollBehavior: false }, () => {
});

// Create workspace and set up index pattern
cy.deleteWorkspaceByName(`${workspace}`);
cy.deleteWorkspaceByName(workspace);
cy.visit('/app/home');
cy.createInitialWorkspaceWithDataSource(`${DATASOURCE_NAME}`, `${workspace}`);
cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspace);

// Create and select index pattern for data_logs_small_time_1*
cy.createWorkspaceIndexPatterns({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ const definedS3Variables = !S3_CLUSTER.url;
// Create workspace
cy.deleteWorkspaceByName(workspace);
cy.visit('/app/home');
cy.createInitialWorkspaceWithDataSource(S3_CLUSTER.name, workspace);
cy.osd.createInitialWorkspaceWithDataSource(S3_CLUSTER.name, WORKSPACE_NAME);
});
afterEach(() => {
cy.deleteWorkspaceByName(workspace);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export const runSavedSearchTests = () => {
// Create workspace
cy.deleteWorkspaceByName(workspaceName);
cy.visit('/app/home');
cy.createInitialWorkspaceWithDataSource(datasourceName, workspaceName);
cy.osd.createInitialWorkspaceWithDataSource(datasourceName, workspaceName);
cy.createWorkspaceIndexPatterns({
workspaceName: workspaceName,
indexPattern: INDEX_PATTERN_WITH_TIME.replace('*', ''),
Expand Down
2 changes: 1 addition & 1 deletion cypress/utils/apps/workspace/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Cypress.Commands.add(
(workspaceName) => {
// Selecting the correct workspace
cy.visit('/app/workspace_list#');
cy.openWorkspaceDashboard(workspaceName);
cy.osd.openWorkspaceDashboard(workspaceName);
// wait until page loads
cy.getElementByTestId('headerAppActionMenu').should('be.visible');
}
Expand Down
43 changes: 43 additions & 0 deletions cypress/utils/command_namespace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

/**
* Initializes a command namespace on the cy object
*
* Ex usage:
* initCommandNamespace(cy, 'osd'); // initializes osd namespace (only needed once per ns)
* cy.osd.add('myNewCommand', (myArg) => ...); // register command to namespace
* cy.osd.myNewCommand('someArg'); // executes command
*
*/
export default function initCommandNamespace(cy, namespace) {
Copy link
Collaborator

@angle943 angle943 Jan 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a comment briefly explaining what this does can be helpful as the function itself is pretty abstract, and if we can have a way of making the Typescript declaration files work with this pattern

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 I'll add comments here to better explain this module. It's challenging to get meaningful TS types for free here since namespaces and their commands are dynamically defined at module resolution, but I can definitely take a look at making the definitions for the two commands I migrated over.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some comments and type definitions. Let me know what you think.

/**
* this proxy is responsible for intercepting access to properties
* it's what allows us to dynamically define properties at runtime like cy.osd.myNewCommand
*/
cy[namespace] = new Proxy(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cool stuff!

{
// register a new namespaced command with cypress (ex. osd:myNewCommand)
add(commandName, callback) {
Cypress.Commands.add(namespaceCommand(commandName), callback);
},
},
{
get(target, property) {
if (target[property]) {
// return reserved property (add method)
return target[property];
}

// return the mapped namespace command (ex. myNewCommand returns the osd:myNewCommand command)
return cy[namespaceCommand(property)];
},
}
);

function namespaceCommand(commandName) {
return `${namespace}:${commandName}`;
}
}
8 changes: 5 additions & 3 deletions cypress/utils/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

import { BASE_PATH } from './constants';
import { TestFixtureHandler } from '../lib/test_fixture_handler';
import initCommandNamespace from './command_namespace';

initCommandNamespace(cy, 'osd');

// This function does not delete all indices
Cypress.Commands.add('deleteAllIndices', () => {
Expand Down Expand Up @@ -322,9 +325,8 @@ Cypress.Commands.add('deleteWorkspace', (workspaceName) => {
cy.contains(/successfully/);
});

Cypress.Commands.add('createInitialWorkspaceWithDataSource', (dataSourceTitle, workspaceName) => {
cy.osd.add('createInitialWorkspaceWithDataSource', (dataSourceTitle, workspaceName) => {
cy.intercept('POST', '/api/workspaces').as('createWorkspaceInterception');

cy.getElementByTestId('workspace-initial-card-createWorkspace-button')
.should('be.visible')
.click();
Expand All @@ -351,7 +353,7 @@ Cypress.Commands.add('createInitialWorkspaceWithDataSource', (dataSourceTitle, w
cy.contains(/successfully/);
});

Cypress.Commands.add('openWorkspaceDashboard', (workspaceName) => {
cy.osd.add('openWorkspaceDashboard', (workspaceName) => {
cy.getElementByTestId('workspace-select-button').should('exist').click();
cy.getElementByTestId('workspace-menu-manage-button').should('exist').click();
cy.get('.euiBasicTable')
Expand Down
2 changes: 1 addition & 1 deletion cypress/utils/dashboards/remove_workspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export function removeSampleDataAndWorkspace(url, workspaceName) {
describe('removing workspace/sampledata', () => {
it('remove workspace', () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not specific to this pr but how come this a utils file if it's a test ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe because this can be re-used across a number of tests. For example, I write a new test and I want to remove a workspace as a part of this test and get solid logs of which parts failed or succeed as a part of that process.

cy.visit(`${url}/app/workspace_list`);
cy.openWorkspaceDashboard(workspaceName);
cy.osd.openWorkspaceDashboard(workspaceName);
cy.getElementByTestId('toggleNavButton').eq(0).should('exist').click();
cy.wait(3000);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not specifc to this pr but how come we opt for the cy.wait instead of using something like timeout

example:

cy.get("#form-name", {timeout: 10000}).type("Mike Johnson")

https://docs.cypress.io/app/core-concepts/retry-ability#Timeouts

so we could put an increased timeout on the next line. cy.getElementByTestId (we might have to modify it if it's not available for that function).

like

Suggested change
cy.wait(3000);
cy.getElementByTestId('collapsibleNavAppLink-workspace_detail', { timeout: 10000 }).should('exist').click();

then instead of an ambiguous wait time which could get flaky it will just keep retrying for the element until it sees it for 10000 ms

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I agree we shouldn't use arbitrary waits given these are flaky and introduce race conditions. I'm a little weary of addressing in this PR since I'm not confident that I'll be able to address easily with the confidence that I won't break anything given I have somewhat limited context in our integration tests.

cy.getElementByTestId('collapsibleNavAppLink-workspace_detail').should('exist').click();
Expand Down
36 changes: 19 additions & 17 deletions cypress/utils/dashboards/setup_workspace.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,29 @@
const dataSourceTitle = Cypress.env('dataSourceTitle');

export function createWorkspaceAndSampleData(url, workspaceName) {
describe('checking home page', () => {
it('checking workspace initial page', () => {
cy.visit(`${url}/app/home`);
cy.getElementByTestId('workspace-initial-card-createWorkspace-button').should('be.visible');
describe('setup workspace', () => {
describe('checking home page', () => {
it('checking workspace initial page', () => {
cy.visit(`${url}/app/home`);
cy.getElementByTestId('workspace-initial-card-createWorkspace-button').should('be.visible');
});
});
});

describe('creating workspace', () => {
it('creating workspace with data source', () => {
cy.visit(`${url}/app/home`);
cy.createInitialWorkspaceWithDataSource(dataSourceTitle, workspaceName);
cy.wait(2000);
describe('creating workspace', () => {
it('creating workspace with data source', () => {
cy.visit(`${url}/app/home`);
cy.osd.createInitialWorkspaceWithDataSource(dataSourceTitle, workspaceName);
cy.wait(2000);
});
});
});

describe('adding sample data to workspace', () => {
it('add sample data to data source', () => {
cy.visit(`${url}/app/workspace_list`);
cy.openWorkspaceDashboard(workspaceName);
cy.openSampleDataPage();
cy.addSampleDataToDataSource(dataSourceTitle);
describe('adding sample data to workspace', () => {
it('add sample data to data source', () => {
cy.visit(`${url}/app/workspace_list`);
cy.osd.openWorkspaceDashboard(workspaceName);
cy.openSampleDataPage();
cy.addSampleDataToDataSource(dataSourceTitle);
});
});
});
}
24 changes: 16 additions & 8 deletions cypress/utils/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,21 @@ declare namespace Cypress {
*/
drag<S = any>(targetSelector: string): Chainable<S>;

/**
* Creates workspace and attaches it to the provided data source
* It also saves the created workspace id as the alias @WORKSPACE_ID
*/
createInitialWorkspaceWithDataSource<S = any>(
dataSourceTitle: string,
workspaceName: string
): Chainable<S>;
// osd namespace
osd: {
/**
* Creates workspace and attaches it to the provided data source
* It also saves the created workspace id as the alias @WORKSPACE_ID
*/
createInitialWorkspaceWithDataSource<S = any>(
dataSourceTitle: string,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: while we are in the neighborhood i wonder if it makes sense to pass an object incase we want to add more details to the workspace or the data source

like

  {  dataSourceTitle: string, workspaceName: string }

the other thing is i'm not super positive if data source title is unique all the time. i think through the UI it is impossible to recreate a duplicate name but via saved objects and APIs you can create a data source with a title identical to another data source. should we not be utilizing the ID? data source should be a saved object and saved object id is always unique.

workspaceName: string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: workspace should be a saved object too i believe. if it is then i think workspaceTitle would be more accurate since the saved object the field is title i believe

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a little hesitant to change the terminology just because it looks like workspaceName is already used heavily in the testing code and in the non-testing code as well: https://github.com/search?q=repo%3Aopensearch-project%2FOpenSearch-Dashboards%20workspaceName&type=code

): Chainable<S>;

/**
* Opens workspace dashboard
*/
openWorkspaceDashboard<S = any>(workspaceName: string): Chainable<S>;
};
}
}
Loading