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

test: user-page-models #9084

Merged
merged 34 commits into from
Apr 4, 2024
Merged

test: user-page-models #9084

merged 34 commits into from
Apr 4, 2024

Conversation

JComins000
Copy link
Contributor

@JComins000 JComins000 commented Apr 1, 2024

Description

This should be most of the page model changes that come with the user tests. This includes the nav sidebar and interactive tables, and all the other pieces of the user admin page.

There's also a test pattern here where we begin test setup with creating a user, and teardown by deactivating it, all through the UI. Unfortunately, I couldn't find a way to delete test users. We would want to consider running teardown at test setup time as well, or maybe a separate reaper script. Neither are happening at this moment, so this would be a good place to begin that discussion.

Test Plan

Commentary (optional)

Checklist

  • Changes have been manually QA'd
  • User-facing API changes need the "User-facing API Change" label.
  • Release notes should be added as a separate file under docs/release-notes/.
    See Release Note for details.
  • Licenses should be included for new code which was copied and/or modified from any external code.

Ticket

INFENG-455

@JComins000 JComins000 requested a review from a team as a code owner April 1, 2024 23:24
@JComins000 JComins000 requested a review from ashtonG April 1, 2024 23:24
@cla-bot cla-bot bot added the cla-signed label Apr 1, 2024
Copy link

netlify bot commented Apr 1, 2024

Deploy Preview for determined-ui ready!

Name Link
🔨 Latest commit 89c1f52
🔍 Latest deploy log https://app.netlify.com/sites/determined-ui/deploys/660f087b62f777000886434c
😎 Deploy Preview https://deploy-preview-9084--determined-ui.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

Copy link

codecov bot commented Apr 1, 2024

Codecov Report

Attention: Patch coverage is 5.81948% with 793 lines in your changes are missing coverage. Please review.

Project coverage is 40.30%. Comparing base (f78b9aa) to head (89c1f52).
Report is 12 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9084      +/-   ##
==========================================
- Coverage   47.07%   40.30%   -6.78%     
==========================================
  Files        1155      848     -307     
  Lines      142400   103887   -38513     
  Branches     2421     2444      +23     
==========================================
- Hits        67034    41869   -25165     
+ Misses      75176    61813   -13363     
- Partials      190      205      +15     
Flag Coverage Δ
harness ?
web 38.51% <5.81%> (-0.44%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files Coverage Δ
...bui/react/src/components/AddUsersToGroupsModal.tsx 78.48% <100.00%> (ø)
...bui/react/src/components/ChangeUserStatusModal.tsx 84.21% <100.00%> (ø)
webui/react/src/components/CreateUserModal.tsx 90.29% <100.00%> (+0.74%) ⬆️
webui/react/src/components/SetUserRolesModal.tsx 73.03% <100.00%> (+0.30%) ⬆️
webui/react/src/components/SkeletonSection.tsx 82.35% <100.00%> (ø)
...ui/react/src/components/Table/InteractiveTable.tsx 70.76% <100.00%> (+0.17%) ⬆️
webui/react/src/components/Table/SkeletonTable.tsx 97.22% <100.00%> (ø)
webui/react/src/pages/Admin/UserManagement.tsx 83.39% <100.00%> (+0.11%) ⬆️
webui/react/src/components/Navigation.tsx 0.00% <0.00%> (ø)
webui/react/src/e2e/models/pages/SignIn.ts 0.00% <0.00%> (ø)
... and 22 more

... and 326 files with indirect coverage changes

@JComins000 JComins000 force-pushed the jcom/INFENG-455/user-tests branch 2 times, most recently from 2b40ecf to 1847fbb Compare April 2, 2024 15:25
Copy link
Contributor

@djanicekpach djanicekpach left a comment

Choose a reason for hiding this comment

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

Looks good, mostly style comments/questions

data-testid="username"
disabled={!!user}
maxLength={128}
placeholder="Username"
Copy link
Contributor

Choose a reason for hiding this comment

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

Place holder changed here as well. Was that intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah the space was bugging me. It was intentional if reviewers are okay with it

Copy link
Contributor

Choose a reason for hiding this comment

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

let's not introduce copy changes in the testing pr.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

just fyi, "username" is used elsewhere as well. I'll make another PR for the fix if you're okay with it
image

*/
get root(): BasePage {
let root: parentTypes = this._parent;
for (; !(root instanceof BasePage); root = root._parent) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think I prefer while here. Just feels better to me than having 2 empty fields

Suggested change
for (; !(root instanceof BasePage); root = root._parent) {
while(!(root instanceof BasePage)){
root = root._parent
}

debugComponentVisible(component: BaseComponent): void {
const componentTree: parentTypes[] = [];
let root: parentTypes = component;
for (; !(root instanceof BasePage); root = root._parent) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same style comment as the other for vs. while line. If you really want to get fancy you could make an iterator function for this that runs the same operation on each element, but probably overkill.

debugComponentVisible(component: BaseComponent): void {
const componentTree: parentTypes[] = [];
let root: parentTypes = component;
for (; !(root instanceof BasePage); root = root._parent) {
Copy link
Contributor

Choose a reason for hiding this comment

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

the underscore in _parent implies private/protected to me, so to access it outside the inheritance hierarchy, I think we either should have a getter for this field, or remove the underscore and allow it to be public. I think I prefer the getter option.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

why do you prefer the getter? it's already readonly, so i don't think we need to hide the attribute. i'd rather remove the underscore

* @param {string} [obj.selector] - Used instead of `defaultSelector`
*/
export class AddUsersToGroupsModal extends Modal {
static override defaultSelector: string = Modal.defaultSelector;
Copy link
Contributor

Choose a reason for hiding this comment

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

do we actually have to override this if we are just using the the parent selector?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes. another reason to switch to instance property

await userManagementPage.createUserModal.username.pwLocator.fill(username);
await userManagementPage.createUserModal.footer.submit.pwLocator.click();
const newIDs = await userManagementPage.table.table.newRowKeys(oldIDs);
expect(newIDs, `newids ${newIDs}, oldids ${oldIDs}`).toHaveLength(1);
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we get the ID from the username? If the username has a uuid do we even need the internal ID for the test? We could just find the row with the username.

readonly username: BaseComponent = new BaseComponent({ parent: this.form, selector: "input[data-testid='username']" });
readonly password: BaseComponent = new BaseComponent({ parent: this.form, selector: "input[data-testid='password']" });
readonly submit: BaseComponent = new BaseComponent({ parent: this.form, selector: "button[data-testid='submit']" });
readonly #form: BaseComponent = new BaseComponent({ parent: this, selector: `form` });
Copy link
Contributor

Choose a reason for hiding this comment

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

For my own edification, why did this switch to having # starting the variable?

Copy link
Contributor Author

@JComins000 JComins000 Apr 2, 2024

Choose a reason for hiding this comment

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

# is for private.
I was thinking it's useful for the hierarchy, but we never .click() or .fill() it's pwlocator.

* @param {string} value - value of the row attribute
*/
return (value: string) => {
// TODO default selector should be instance property to make this easier. We want RowType.defaultSelector
Copy link
Contributor

Choose a reason for hiding this comment

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

could you talk a little about how making the default selector an instance property would make this easier?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah, here's the change
#9096

the problem is that we want to use selector: RowType.defaultSelector + [${key}="${value}"],, but TS doesn't know about any static elements on the generic class RowType. I put Row.defaultSelector here to make the compiler happy, and it works for now.

class UserRow extends Row {
  static override defaultSelector: string = Row.defaultSelector;

With the instance property, the lines here change to

      return new this.#rowType({
        attachment: `[${key}="${value}"]`,

Copy link
Contributor

Choose a reason for hiding this comment

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

that's fixable -- the issue you're running into is that the type of a class is its instance type in typescript -- when referring to the class itself, you want the typeof the class:

class Coordinates {
  static memo = "hello" as const
  x = 0
  y = 0
}

const c: Coordinates = new Coordinates();
const s: (typeof Coordinates)['memo'] = "hello"

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah I didn't like using the [] syntax to access object properties. It was also telling me a few errors when I had tried
image

Copy link
Contributor

Choose a reason for hiding this comment

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

the error message is saying that you're using the type where you want to use a value -- shouldn't it be this.rowType.defaultSelector?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, but TS doesn't actually know that the static value exists
image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

and here's the implementation from basecomponent.ts

export abstract class NamedComponent extends BaseComponent {
  constructor({ parent, selector }: { parent: parentTypes; selector: string }) {
    super({ parent, selector });
    requireStaticArgs(this.constructor, ['defaultSelector']);
  }
}

// TODO remove this for instance properties instead. static has been difficult to work with
export function requireStaticArgs<T extends object>(obj: T, requiredProperties: string[]): void {
  requiredProperties.forEach((requiredProp) => {
    if (!Object.hasOwn(obj, requiredProp)) {
      throw new Error(`${obj} must declare a static ${requiredProp}!`);
    }
  });
}

Copy link
Contributor

Choose a reason for hiding this comment

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

that's because of the RowTypeGeneric -- you don't need that with the typeof because it knows the type of the constructor already and changing the type of the constructor would break the extension

JComins000 and others added 2 commits April 3, 2024 12:06
Co-authored-by: Ashton G. <ashton.galloway@hpe.com>
Co-authored-by: Ashton G. <ashton.galloway@hpe.com>
await expect(page).toHaveURL(userManagementPage.url);
});

// test('Users table count matches admin page users tab', async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

delete comment before merge

@JComins000 JComins000 enabled auto-merge (squash) April 4, 2024 20:08
@JComins000 JComins000 merged commit 2c6fec7 into main Apr 4, 2024
66 of 80 checks passed
@JComins000 JComins000 deleted the jcom/INFENG-455/user-tests branch April 4, 2024 20:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants