-
Notifications
You must be signed in to change notification settings - Fork 8.3k
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
[FTR] Refactor toasts svc #174222
Merged
Merged
[FTR] Refactor toasts svc #174222
Changes from 85 commits
Commits
Show all changes
87 commits
Select commit
Hold shift + click to select a range
27af4c5
[FTR] Move toasts service to shared location
wayneseymour 23638b5
Rename dismissToast to dismissToastByIndex.
wayneseymour 472fbd2
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine cbfde4c
Use new service instead.
wayneseymour 1d19997
Refactor to shared pkg.
wayneseymour 30780d4
Refactor to shared pkg.
wayneseymour 3a9a1bd
Refactor to shared pkg.
wayneseymour bfdcab0
Drop dup symbol.
wayneseymour 1fefe7c
Fixup symbols
wayneseymour 7e4bbfe
Fixup symbols
wayneseymour ee104fb
Mv to toasts svc.
wayneseymour adfeb0a
Refactor name to be most specific.
wayneseymour 981e1f4
Add type.
wayneseymour 6de0f9e
Cleanup.
wayneseymour 01d3956
Cleanup.
wayneseymour 5441085
More refactoring.
wayneseymour bc6f2ba
de duplicate
wayneseymour 4adb2df
correct symbol name
wayneseymour 18cdfd5
[FTR] Move toasts service to shared location
wayneseymour f4f90c3
Rename dismissToast to dismissToastByIndex.
wayneseymour 9e69f15
[CI] Auto-commit changed files from 'node scripts/lint_ts_projects --…
kibanamachine 0a6f0d1
Use new service instead.
wayneseymour e43130b
Refactor to shared pkg.
wayneseymour d01cb32
Refactor to shared pkg.
wayneseymour 842053a
Refactor to shared pkg.
wayneseymour cf96415
Drop dup symbol.
wayneseymour 432b1aa
Fixup symbols
wayneseymour a8a552c
Fixup symbols
wayneseymour 41f6ad0
Mv to toasts svc.
wayneseymour 65cc4ff
Refactor name to be most specific.
wayneseymour 79e04c5
Add type.
wayneseymour b54d554
Cleanup.
wayneseymour b843213
Cleanup.
wayneseymour afd49cc
More refactoring.
wayneseymour 583503c
de duplicate
wayneseymour c5e086c
correct symbol name
wayneseymour dff9fe2
fixup broken test
wayneseymour 137f331
Merge branch 'refactor-toasts-svc' of github.com:wayneseymour/kibana …
wayneseymour 6ff4ce7
De-dupe; drop clearAllToasts() in favor of
wayneseymour 4475726
Drop what seems to be an un-used fn call.
wayneseymour 66a6f26
Merge branch 'main' into refactor-toasts-svc
kibanamachine 4083f00
Merge branch 'main' into refactor-toasts-svc
kibanamachine eff997c
Merge branch 'main' into refactor-toasts-svc
kibanamachine 4182039
Merge branch 'main' into refactor-toasts-svc
kibanamachine c5a336d
drop unused export
wayneseymour c2d9837
rename symbol for consistency
wayneseymour 72a33bd
revert this fn to where it was, due to it's specificity
wayneseymour 9964e4a
Add getToastTitleByIndex() method.
wayneseymour 4b43dfb
Use 'new' by index methods for toasts.
wayneseymour 1844ec3
Merge branch 'main' of github.com:elastic/kibana into refactor-toasts…
wayneseymour 8450696
fixup connector
wayneseymour a27a082
Drop duplicate.
wayneseymour 50a1248
Merge branch 'main' of github.com:elastic/kibana into refactor-toasts…
wayneseymour 3037066
use get toast count method instead
wayneseymour 9feb3f0
Use getToastTitleByIndex() method instead.
wayneseymour 2537637
Merge branch 'main' into refactor-toasts-svc
kibanamachine b7ded72
drop log; for now
wayneseymour 56a8333
revert
wayneseymour aae2e19
drop unused
wayneseymour fdc589c
drop unused
wayneseymour e91d574
Merge branch 'main' of github.com:elastic/kibana into refactor-toasts…
wayneseymour 7968bba
fixup stale element issue
wayneseymour ebe2248
Merge branch 'main' of github.com:elastic/kibana into refactor-toasts…
wayneseymour 3624350
Take Robert's advice and refactor / merge
wayneseymour 2f4c166
Rename and clean up this method a bit, and
wayneseymour 6b3a0e7
Drop debug logging.
wayneseymour 6f3832b
Drop issue link per code review.
wayneseymour f0d7a49
Rename per cr
wayneseymour d4d5fc0
Rename symbols per cr.
wayneseymour 25282e8
revert to try to preserve history
wayneseymour ab2207f
use (git mv src dest) to try to preserve mv history
wayneseymour 4186fe0
add the changes back
wayneseymour 05359f7
Merge branch 'main' of github.com:elastic/kibana into refactor-toasts…
wayneseymour e0746c1
split method into 2 methods per cr.
wayneseymour 4ea4a35
More idiomatic.
wayneseymour d7ca2f5
Merge branch 'main' of github.com:elastic/kibana into refactor-toasts…
wayneseymour 8772ca9
whoops, wrong method.
wayneseymour 1f1e9ff
the OOP oops :)
wayneseymour fb322ef
fixup symbols
wayneseymour 940f838
Merge branch 'main' of github.com:elastic/kibana into refactor-toasts…
wayneseymour 44c3782
Merge branch 'main' into refactor-toasts-svc
kibanamachine 62613eb
Merge branch 'main' into refactor-toasts-svc
kibanamachine 5db7143
cleanup and dog food by using the new
wayneseymour 7032a54
Change method internals to be how it was.
wayneseymour 4fbed13
Merge branch 'main' into refactor-toasts-svc
kibanamachine aa9fe63
fixup comment, per cr
wayneseymour 14c4154
Merge branch 'refactor-toasts-svc' of github.com:wayneseymour/kibana …
wayneseymour File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
156 changes: 156 additions & 0 deletions
156
packages/kbn-ftr-common-functional-ui-services/services/toasts.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
/* | ||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one | ||
* or more contributor license agreements. Licensed under the Elastic License | ||
* 2.0 and the Server Side Public License, v 1; you may not use this file except | ||
* in compliance with, at your election, the Elastic License 2.0 or the Server | ||
* Side Public License, v 1. | ||
*/ | ||
|
||
import expect from '@kbn/expect'; | ||
import { FtrService } from './ftr_provider_context'; | ||
import { WebElementWrapper } from './web_element_wrapper'; | ||
|
||
export class ToastsService extends FtrService { | ||
private readonly testSubjects = this.ctx.getService('testSubjects'); | ||
private readonly retry = this.ctx.getService('retry'); | ||
private readonly find = this.ctx.getService('find'); | ||
private readonly config = this.ctx.getService('config'); | ||
private readonly defaultFindTimeout = this.config.get('timeouts.find'); | ||
/** | ||
* Returns the title and message of a specific error toast. | ||
* This method is specific to toasts created via `.addError` since they contain | ||
* an additional button, that should not be part of the message. | ||
* | ||
* @param index The index of the toast (1-based, NOT 0-based!) of the toast. Use first by default. | ||
* @param titleOnly If this is true, only the title of the error message is returned. There are error messages that only contain a title, no message. | ||
* @returns The title and message of the specified error toast. | ||
*/ | ||
public async getErrorByIndex( | ||
index: number = 1, | ||
titleOnly: boolean = false | ||
): Promise<{ title: string; message?: string }> { | ||
const title = await this.getTitleByIndex(index); | ||
if (titleOnly) return { title }; | ||
|
||
const toast = await this.getElementByIndex(index); | ||
const messageElement = await this.testSubjects.findDescendant('errorToastMessage', toast); | ||
const message: string = await messageElement.getVisibleText(); | ||
|
||
return { title, message }; | ||
} | ||
|
||
public async toastMessageByTestSubj(testSubj = 'csp:toast-success') { | ||
const testSubjSvc = this.testSubjects; | ||
return { | ||
async getElement(): Promise<WebElementWrapper> { | ||
return await testSubjSvc.find(testSubj); | ||
}, | ||
async clickToastMessageLink(linkTestSubj = 'csp:toast-success-link') { | ||
const element = await this.getElement(); | ||
const link = await element.findByTestSubject(linkTestSubj); | ||
await link.click(); | ||
}, | ||
}; | ||
} | ||
|
||
/** | ||
* Dismiss a specific toast from the toast list. Since toasts usually should time out themselves, | ||
* you only need to call this for permanent toasts (e.g. error toasts). | ||
* | ||
* @param index The 1-based index of the toast to dismiss. Use first by default. | ||
*/ | ||
public async dismissByIndex(index: number = 1): Promise<void> { | ||
const toast = await this.getElementByIndex(index); | ||
await toast.moveMouseTo(); | ||
const dismissButton = await this.testSubjects.findDescendant('toastCloseButton', toast); | ||
await dismissButton.click(); | ||
} | ||
|
||
public async dismissIfExists(): Promise<void> { | ||
const toastShown = await this.find.existsByCssSelector('.euiToast'); | ||
if (toastShown) { | ||
try { | ||
await this.testSubjects.click('toastCloseButton'); | ||
} catch (err) { | ||
// ignore errors, toast clear themselves after timeout | ||
} | ||
} | ||
} | ||
|
||
public async getTitleAndDismiss(): Promise<string> { | ||
const toast = await this.find.byCssSelector('.euiToast', 6 * this.defaultFindTimeout); | ||
await toast.moveMouseTo(); | ||
const title = await (await this.testSubjects.find('euiToastHeader__title')).getVisibleText(); | ||
|
||
await this.testSubjects.click('toastCloseButton'); | ||
return title; | ||
} | ||
|
||
public async dismiss(): Promise<void> { | ||
await this.testSubjects.click('toastCloseButton', 6 * this.defaultFindTimeout); | ||
} | ||
|
||
public async dismissAll(): Promise<void> { | ||
const allToastElements = await this.getAll(); | ||
|
||
if (allToastElements.length === 0) return; | ||
|
||
for (const toastElement of allToastElements) { | ||
try { | ||
await toastElement.moveMouseTo(); | ||
const closeBtn = await toastElement.findByTestSubject('toastCloseButton'); | ||
await closeBtn.click(); | ||
} catch (err) { | ||
// ignore errors, toast clear themselves after timeout | ||
} | ||
} | ||
} | ||
|
||
public async dismissAllWithChecks(): Promise<void> { | ||
await this.retry.tryForTime(30 * 1000, async (): Promise<void> => { | ||
await this.dismissAll(); | ||
await this.assertCount(0); | ||
}); | ||
} | ||
|
||
public async assertCount(expectedCount: number): Promise<void> { | ||
await this.retry.tryForTime(5 * 1000, async (): Promise<void> => { | ||
const toastCount = await this.getCount({ timeout: 1000 }); | ||
expect(toastCount).to.eql( | ||
expectedCount, | ||
`Toast count should be ${expectedCount} (got ${toastCount})` | ||
); | ||
}); | ||
} | ||
|
||
public async getElementByIndex(index: number): Promise<WebElementWrapper> { | ||
return await (await this.getGlobalList()).findByCssSelector(`.euiToast:nth-child(${index})`); | ||
} | ||
|
||
public async getTitleByIndex(index: number): Promise<string> { | ||
const resultToast = await this.getElementByIndex(index); | ||
const titleElement = await this.testSubjects.findDescendant('euiToastHeader', resultToast); | ||
const title: string = await titleElement.getVisibleText(); | ||
return title; | ||
} | ||
|
||
public async getContentByIndex(index: number): Promise<string> { | ||
const elem = await this.getElementByIndex(index); | ||
return await elem.getVisibleText(); | ||
} | ||
|
||
public async getAll(): Promise<WebElementWrapper[]> { | ||
const list = await this.getGlobalList(); | ||
return await list.findAllByCssSelector(`.euiToast`); | ||
} | ||
|
||
private async getGlobalList(options?: { timeout?: number }): Promise<WebElementWrapper> { | ||
return await this.testSubjects.find('globalToastList', options?.timeout); | ||
} | ||
|
||
public async getCount(options?: { timeout?: number }): Promise<number> { | ||
const list = await this.getGlobalList(options); | ||
const toasts = await list.findAllByCssSelector(`.euiToast`, options?.timeout); | ||
return toasts.length; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 think this construction is not ideal. I know it has been taken over as-is from the old implementation, however it's always just called like this:
const toastMessage = await (await toasts.toastMessageByTestSubj()).getElement();
so there's no real benefit with the nested methods and IMO just makes the code more complicated to read, write and maintain. I'd suggest to refactor this bit, either in this PR or in a follow up.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.
Agree with Robert. We should not expose WebDriver interfaces like
.getElement()
, but only toast specific actions: close(), getText(), waitToDisappear().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.
@pheyos @wayneseymour wdyt about removing
toast
from methods name?toasts.dismissAllToasts();
=>toasts.dismissAll();
toasts.closeToast();
=>toasts.close();
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.
Sounds good to me 👍
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 completely concur!
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.
Will be resolved by: #176570