In v4.14+ Grouper has better attributes in the UI HTML DOM to navigate programmatically. The playwright library will be available in the container by setting an environment variable
Playwright will be an option to run inside of Grouper to make scripts that can validate the UI.
Methods will be available to perform certain actions in the UI in a way that is easy to script and will survive upgrades.
These methods are idempotent, so if the state is already set, then it is still a success. If there is a problem then
Use the Playwright recorder to simulate a log in or other purposes
Category | Action | Class |
---|---|---|
Daemon | View errors | GrouperUiBrowserDaemonViewErrors |
General | Verify version | GrouperUiBrowserGeneralVerifyVersion |
Group | Find group | GrouperUiBrowserGroupFinder |
Create group | GrouperUiBrowserGroupCreate | |
Edit group | GrouperUiBrowserGroupEdit | |
Delete group | GrouperUiBrowserGroupDelete | |
GSH template | Run template | GrouperUiBrowserTemplateRun |
Custom UI | View custom UI | GrouperUiBrowserCustomUiView |
Membership | Find membership | GrouperUiBrowserMembershipFinder |
Add membership | GrouperUiBrowserMembershipAdd | |
Remove membership | GrouperUiBrowserMembershipRemove | |
Provisioning | Assign group provisionable | GrouperUiBrowserProvisioningAssignGroup |
Remove group provisionable | GrouperUiBrowserProvisioningRemoveGroup |
DOM attributes and standards
- For these methods there will be strong HTML attributes to use for CSS selectors
- Selectors are unique in a page
- Externalized text will not be used
- Prefer to use the "id" of the HTML element
Custom grouper attributes are added to find html elements. (start with "data-gr-" )
<a href="" data-gr-browse-folder-name="some:folder:name">...</a>
- Full paths will be used
- Display names will not be used
- Values will be escaped
- Methods will start by navigating to the main page
- Each click will validate that the UI changed
- Hidden HTML elements can be used
- These operations will run as GrouperSystem
Using these methods
Setup some Playwright objects
import com.microsoft.playwright.Browser; import com.microsoft.playwright.BrowserType; import com.microsoft.playwright.Page; import com.microsoft.playwright.Playwright; import com.microsoft.playwright.options.AriaRole; import edu.internet2.middleware.grouper.app.browser.*; Playwright playwright = Playwright.create(); BrowserType chromium = playwright.chromium(); Browser browser = chromium.launch(new BrowserType.LaunchOptions().setHeadless(true)); Page page = browser.newPage(); GrouperPage grouperPage = new GrouperPage(); grouperPage.setPage(page);
Navigate to the Grouper being tested
// either use the built in config for the Grouper UI String uiUrl = GrouperConfig.retrieveConfig().propertyValueStringRequired("grouper.ui.url"); // or hard code a url or use another config String uiUrl = "https://grouper.institution.edu"; // note this defaults to grouper.properties grouper.ui.url // so you do not need to set this if testing this env grouperPage.assignUrl(uiUrl); // note this is the default so you probably do not need to do this grouperPage.assignContext("/grouper"); page.navigate(grouperPage.getUrl());
Authenticate to the UI (e.g. with a test account). Note you need to record this with selenium (and set the language to Java), or look at the DOM of your login screens
page.getByLabel("Username").click(); page.getByLabel("Username").fill("someTestUserName"); page.getByLabel("Username").press("Tab"); page.getByLabel("Password", new Page.GetByLabelOptions().setExact(true)).click(); page.getByLabel("Password", new Page.GetByLabelOptions().setExact(true)).fill(GrouperConfig.retrieveConfig().propertyValueStringRequired("someTestUserName.pass")); page.getByLabel("Password", new Page.GetByLabelOptions().setExact(true)).press("Enter"); // does your test account have duo? accept the push page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("No, other people use this")).click();
Call the API methods above
import edu.internet2.middleware.grouper.grouperUi.browser.*; // add a user to a group new GrouperUiBrowserMembershipAdd().assignGrouperPage(grouperPage). assignGroupName("a:b:c").assignSubjectId("10021368").assignSubjectSourceId("schoolPerson").browse(); // make a group provisionable new GrouperUiBrowserProvisioningAssignGroup().assignGrouperPage(grouperPage). assignGroupName("a:b:c").assignProvisionerConfigId("myLdapProvisioner").browse(); // etc