Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
14 changes: 7 additions & 7 deletions apps/E2E/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@
"@fluentui-react-native/focus-zone": "workspace:*",
"@fluentui-react-native/kit-config": "workspace:*",
"@fluentui-react-native/scripts": "workspace:*",
"@office-iss/react-native-win32": "^0.74.0",
"@react-native/metro-babel-transformer": "^0.74.0",
"@office-iss/react-native-win32": "^0.81.0",
"@react-native/metro-babel-transformer": "^0.81.0",
"@rnx-kit/metro-config": "catalog:",
"@types/jasmine": "catalog:",
"@types/node": "catalog:",
"@types/react": "~18.2.0",
"@types/react": "~19.1.0",
"@wdio/appium-service": "catalog:",
"@wdio/cli": "catalog:",
"@wdio/globals": "catalog:",
Expand All @@ -72,10 +72,10 @@
"cross-env": "catalog:",
"expect-webdriverio": "catalog:",
"metro-config": "^0.80.3",
"react": "18.2.0",
"react-native": "^0.74.0",
"react-native-macos": "^0.74.0",
"react-native-windows": "^0.74.0",
"react": "19.1.0",
"react-native": "^0.81.0",
"react-native-macos": "^0.81.0",
"react-native-windows": "^0.81.0",
"rimraf": "catalog:",
"ts-node": "^10.7.0",
"webdriverio": "catalog:"
Expand Down
16 changes: 7 additions & 9 deletions apps/E2E/src/ButtonLegacy/pages/ButtonLegacyPageObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,16 @@ class ButtonLegacyPageObject extends BasePage {
/******************************************************************/

async didOnClickCallbackFire(errorMsg: string): Promise<boolean | void> {
const callbackText = await this._callbackText;
return await this.waitForCondition(async () => await callbackText.isDisplayed(), errorMsg);
return this._callbackText.waitForDisplayed({ timeoutMsg: errorMsg });
}

async resetTest(): Promise<void> {
const callbackText = await this._callbackText;
if (await callbackText.isDisplayed()) {
await (await this._primaryComponent).click();
await this.waitForCondition(
async () => !(await callbackText.isDisplayed()),
'Could not reset test: Clicked button to toggle onClick callback text, but the text failed to hide.',
);
if (await this._callbackText.isDisplayed()) {
await this._primaryComponent.click();
await this._callbackText.waitForDisplayed({
reverse: true,
timeoutMsg: 'Could not reset test: Clicked button to toggle onClick callback text, but the text failed to hide.',
});
}
}

Expand Down
16 changes: 7 additions & 9 deletions apps/E2E/src/ButtonV1/pages/ButtonV1PageObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,16 @@ class ButtonV1PageObject extends BasePage {
/**************** UI Element Interaction Methods ******************/
/******************************************************************/
async waitForOnClickCallbackToFire(errorMsg: string): Promise<boolean | void> {
const callbackText = await this._callbackText;
return await this.waitForCondition(async () => await callbackText.isDisplayed(), errorMsg);
return this._callbackText.waitForDisplayed({ timeoutMsg: errorMsg });
}

async resetTest(): Promise<void> {
const callbackText = await this._callbackText;
if (await callbackText.isDisplayed()) {
await (await this._primaryComponent).click();
await this.waitForCondition(
async () => !(await callbackText.isDisplayed()),
'Could not reset test: Clicked button to toggle onClick callback text, but the text failed to hide.',
);
if (await this._callbackText.isDisplayed()) {
await this._primaryComponent.click();
await this._callbackText.waitForDisplayed({
reverse: true,
timeoutMsg: 'Could not reset test: Clicked button to toggle onClick callback text, but the text failed to hide.',
});
}
}

Expand Down
7 changes: 2 additions & 5 deletions apps/E2E/src/Callout/pages/CalloutPageObject.win.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ class CalloutPageObject extends BasePage {
// This both opens and waits for it to go in view
async openCalloutAndWaitForLoad(): Promise<void> {
if (!(await this.isCalloutOpen())) {
await browser.waitUntil(async () => await this._buttonToOpenCallout.isEnabled(), {
timeout: 15000,
timeoutMsg: 'Button to open the Callout is not enabled.',
});
await this._buttonToOpenCallout.waitForEnabled({ timeoutMsg: 'Button to open the Callout is not enabled.' });

await this._buttonToOpenCallout.click();
await this._primaryComponent.waitForDisplayed({
Expand All @@ -26,7 +23,7 @@ class CalloutPageObject extends BasePage {

async closeCallout(): Promise<void> {
// all we have to do is click outside the callout
await (await this._testPage).click();
this._testPage.click();
}

/*****************************************/
Expand Down
5 changes: 2 additions & 3 deletions apps/E2E/src/CheckboxLegacy/pages/CheckboxLegacyPageObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class CheckboxLegacyPageObject extends BasePage {
/**************** UI Element Interaction Methods ******************/
/******************************************************************/
async isCheckboxChecked(): Promise<boolean> {
const checkbox = await this._primaryComponent;
const checkbox = this._primaryComponent;
if (this.platform === 'windows') {
// for native windows, .isSelected() always returns false. this is a workaround
return (await checkbox.getAttribute(Attribute.ToggleState)) === AttributeValue.on;
Expand Down Expand Up @@ -43,8 +43,7 @@ class CheckboxLegacyPageObject extends BasePage {
* the onChange() callback gets fired, we show / hide the a Text label as the callback gets fired. This way, we know that
* the onChange() callback has fired by checking that the label element is currently displayed. */
async didOnChangeCallbackFire(errorMsg: string): Promise<boolean | void> {
const callbackText = await this._callbackText;
return await this.waitForCondition(async () => await callbackText.isDisplayed(), errorMsg);
return this._callbackText.waitForDisplayed({ timeoutMsg: errorMsg });
}

/*****************************************/
Expand Down
5 changes: 1 addition & 4 deletions apps/E2E/src/Input/pages/InputPageObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@ class InputPageObject extends BasePage {

/* Waits for the text content to get updated to new string. */
async waitForStringUpdate(newState: string, errorMessage: string): Promise<void> {
await this.waitForCondition(
async () => (await (await this._callbackText).getAttribute(AndroidAttribute.Text)) == newState,
errorMessage,
);
await this.waitForCondition(async () => (await this._callbackText.getAttribute(AndroidAttribute.Text)) == newState, errorMessage);
}

/*****************************************/
Expand Down
4 changes: 2 additions & 2 deletions apps/E2E/src/LinkV1/pages/LinkV1PageObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ class LinkV1PageObject extends BasePage {
/**************** UI Element Interaction Methods ******************/
/******************************************************************/
async didOnPressCallbackFire(errMsg: string): Promise<boolean | void> {
const callbackText = await By(LINKV1_NO_A11Y_LABEL_COMPONENT);
return await this.waitForCondition(async () => await callbackText.isDisplayed(), errMsg);
const callbackText = By(LINKV1_NO_A11Y_LABEL_COMPONENT);
return callbackText.waitForDisplayed({ timeoutMsg: errMsg });
}

/*****************************************/
Expand Down
6 changes: 3 additions & 3 deletions apps/E2E/src/Overflow/pages/OverflowPageObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ class OverflowPageObject extends BasePage {
}

async itemIsVisible(selector: OverflowItem, errorMsg?: string) {
const item = await this.getOverflowItem(selector);
return this.waitForCondition(async () => await item.isDisplayed(), errorMsg);
const item = this.getOverflowItem(selector);
return item.waitForDisplayed({ timeoutMsg: errorMsg });
}

async menuIsDisplayed(errorMsg?: string) {
return this.waitForCondition(async () => (await this._overflowMenu).isDisplayed(), errorMsg);
return this._overflowMenu.waitForDisplayed({ timeoutMsg: errorMsg });
}

async setOverflowWidth(width: OverflowWidth) {
Expand Down
3 changes: 1 addition & 2 deletions apps/E2E/src/Switch/pages/SwitchPageObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ class SwitchPageObject extends BasePage {
}

async waitForOnChangeCallbackToFire(errorMsg: string): Promise<boolean | void> {
const callbackText = await this._callbackText;
return await this.waitForCondition(async () => await callbackText.isDisplayed(), errorMsg);
return this._callbackText.waitForDisplayed({ timeoutMsg: errorMsg });
}

/*****************************************/
Expand Down
2 changes: 1 addition & 1 deletion apps/E2E/src/TabList/pages/TabListPageObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class TabListPageObject extends BasePage {

// Waits for the TabList's `onTabSelect` callback to fire (changing a text component value). Throws an error if the callback doesn't fire by the end of the timeout.
async waitForCallbackToFire(tabKeyPressed: string, errorMsg: string, timeout?: number): Promise<void> {
const callbackText = await By(TABLIST_CALLBACK_TEXT);
const callbackText = By(TABLIST_CALLBACK_TEXT);
await this.waitForCondition(async () => (await callbackText.getText()) === tabKeyPressed, errorMsg, timeout);
}

Expand Down
67 changes: 42 additions & 25 deletions apps/E2E/src/common/BasePage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,10 @@ export abstract class BasePage {
await this.mobileScrollToComponentButton();
}

await (await this._pageButton).click();
await this._pageButton.click();

// Wait for page to load
return await this.waitForCondition(async () => await this.isPageLoaded(), this.ERRORMESSAGE_PAGELOAD, this.waitForUiEvent, 1500);
return await this.waitForPageToLoad();
}

/*
Expand All @@ -94,35 +94,33 @@ export abstract class BasePage {
* own section on the test page (by default, it's hidden so partners don't see it). This method opens up that testing section.
*/
async enableE2ETesterMode(): Promise<boolean | void> {
const e2eSwitch = await this._e2eSwitch;
await browser.waitUntil(async () => (await e2eSwitch.isDisplayed()) && (await e2eSwitch.isEnabled()), {
timeout: 15000,
timeoutMsg: 'The E2E Switch should be enabled and visible before we interact with it',
});
const e2eSwitch = this._e2eSwitch;
await e2eSwitch.waitForDisplayed({ timeoutMsg: 'E2E Test Switch should be visible to enable it' });
await e2eSwitch.waitForEnabled({ timeoutMsg: 'The E2E Switch should be enabled before we interact with it' });

switch (this.platform) {
// Usually, we use .isSelected() to see if a control (our switch) is checked true or false, but the process is
// different on android because .isSelected() doesn't function as expected on the platform.
case 'android':
if ((await e2eSwitch.getAttribute(AndroidAttribute.Checked)) === 'false') {
await e2eSwitch.click();
await this.waitForCondition(
async () => (await e2eSwitch.getAttribute(AndroidAttribute.Checked)) === 'true',
'Clicked the E2E Mode Switch, but it failed to toggle.',
);
await e2eSwitch.waitUntil(async () => (await e2eSwitch.getAttribute(AndroidAttribute.Checked)) === 'true', {
timeoutMsg: 'Clicked the E2E Mode Switch, but it failed to toggle.',
});
}
break;
default:
if (!(await e2eSwitch.isSelected())) {
await e2eSwitch.click();
await this.waitForCondition(async () => e2eSwitch.isSelected(), 'Clicked the E2E Mode Switch, but it failed to toggle.');
await e2eSwitch.waitUntil(async () => await e2eSwitch.isSelected(), {
timeoutMsg: 'Clicked the E2E Mode Switch, but it failed to toggle.',
});
}
}

return await this.waitForCondition(
async () => await this._e2eSection.isDisplayed(),
'Pressed E2E Mode Switch, but E2E Test Sections failed to display before the timeout.',
);
return await this._e2eSection.waitForDisplayed({
timeoutMsg: 'Pressed E2E Mode Switch, but E2E Test Sections failed to display before the timeout.',
});
}

/**
Expand Down Expand Up @@ -153,16 +151,37 @@ export abstract class BasePage {
return true;
}

/** Wait for the page to load */
async waitForPageToLoad(): Promise<boolean | void> {
return browser.waitUntil(async () => await this.isPageLoaded(), {
timeout: this.waitForUiEvent,
timeoutMsg: this.ERRORMESSAGE_PAGELOAD,
});
}

hasPrimaryComponent() {
return this._primaryComponentName !== DUMMY_CHAR;
}

async isPrimaryComponentDisplayed() {
return this.hasPrimaryComponent() ? this._primaryComponent.isDisplayed() : false;
}

async isTestPageDisplayed() {
return this._pageName !== DUMMY_CHAR ? this._testPage.isDisplayed() : false;
}

/* Returns true if the test page has loaded. To determine if it's loaded, each test page has a specific UI element we attempt to locate.
* If this UI element is located, we know the page as loaded correctly. The UI element we look for is a Text component that contains
* the title of the page (this._testPage returns that UI element) */
async isPageLoaded(): Promise<boolean> {
return (await (await this._testPage).isDisplayed()) || (await this._primaryComponent.isDisplayed());
const [isPageDisplayed, isComponentDisplayed] = await Promise.all([this.isTestPageDisplayed(), this.isPrimaryComponentDisplayed()]);
return isPageDisplayed || isComponentDisplayed;
}

/** Given a WebdriverIO element promise, send a click input to the element. Use this across all PageObject methods and test specs. */
async click(element: ChainablePromiseElement): Promise<void> {
await element.click();
async click(element: ChainablePromiseElement) {
return element.click();
}

/** Given a WebdriverIO element promise, send the passed in list of keys as keyboard inputs. Use this across all PageObject methods and test specs.
Expand All @@ -172,13 +191,13 @@ export abstract class BasePage {
* - Shift tab to the previous element: FocusZonePageObject.sendKeys(FocusZonePageObject.beforeButton, [KEY_SHIFT, KEY_TAB])
* - Escape out of a menu: MenuPageObject.sendKeys(MenuPageObject.item1, [KEY_ESCAPE])
*/
async sendKeys(element: ChainablePromiseElement, keys: Keys[]): Promise<void> {
await element.addValue(keys.join());
async sendKeys(element: ChainablePromiseElement, keys: Keys[]) {
return element.addValue(keys.join());
}

/** Short-hand method for PageObjects to get an element attribute during testing, with attribute being type-enforced. */
async getElementAttribute(element: ChainablePromiseElement, attribute: Attribute) {
return await element.getAttribute(attribute);
return element.getAttribute(attribute);
}

/* Scrolls until the desired test page's button is displayed. We use the scroll viewer UI element as the point to start scrolling.
Expand Down Expand Up @@ -271,7 +290,7 @@ export abstract class BasePage {

/** Waits for the tester app to load by checking if the startup page loads. If the app doesn't load before the timeout, it causes the test to fail. */
async waitForInitialPageToDisplay(): Promise<boolean | void> {
return await this.waitForCondition(async () => await this._initialPage.isDisplayed(), this.ERRORMESSAGE_APPLOAD, BOOT_APP_TIMEOUT);
return this._initialPage.waitForDisplayed({ timeout: BOOT_APP_TIMEOUT, timeoutMsg: this.ERRORMESSAGE_APPLOAD });
}

/* Scrolls to the specified or primary UI test element until it is displayed. */
Expand Down Expand Up @@ -432,15 +451,13 @@ export abstract class BasePage {
// Returns: String
// Returns the identifier of the primary UI element used for testing on the given test page.
get _primaryComponentName(): string {
console.warn('Please verify whether or not your page object should implement _primaryComponentName.');
return DUMMY_CHAR;
}

// Returns: String
// Returns the identifier of the secondary UI element used for testing on the given test page. Often times, we'll want to set a
// prop on one component, and not set it on another to verify certain behaviors. This is why we have this secondary component.
get _secondaryComponentName(): string {
console.warn('Please verify whether or not your page object should implement _secondaryComponentName.');
return DUMMY_CHAR;
}

Expand Down
2 changes: 1 addition & 1 deletion apps/E2E/wdio.conf.macos.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ exports.config = {
waitforTimeout: defaultWaitForTimeout, // Default timeout for all waitForXXX commands.
connectionRetryTimeout: defaultConnectionRetryTimeout, // Timeout for any WebDriver request to a driver or grid.
connectionRetryCount: 2, // Maximum count of request retries to the Selenium server.
specFileRetries: 2, // The number of times to retry the entire spec file when it fails as a whole.
specFileRetries: 1, // The number of times to retry the entire spec file when it fails as a whole.

port: 4723, // default appium port
services: [
Expand Down
2 changes: 1 addition & 1 deletion apps/E2E/wdio.conf.win32.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ exports.config = {
waitforTimeout: defaultWaitForTimeout, // Default timeout for all waitForXXX commands.
connectionRetryTimeout: defaultConnectionRetryTimeout, // Timeout for any WebDriver request to a driver or grid.
connectionRetryCount: 2, // Maximum count of request retries to the Selenium server.
specFileRetries: 2, // The number of times to retry the entire spec file when it fails as a whole.
specFileRetries: 1, // The number of times to retry the entire spec file when it fails as a whole.

port: 4723, // default appium port
services: [
Expand Down
2 changes: 1 addition & 1 deletion apps/E2E/wdio.conf.windows.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ exports.config = {
waitforTimeout: defaultWaitForTimeout, // Default timeout for all waitForXXX commands.
connectionRetryTimeout: defaultConnectionRetryTimeout, // Timeout for any WebDriver request to a driver or grid.
connectionRetryCount: 2, // Maximum count of request retries to the Selenium server.
specFileRetries: 2, // The number of times to retry the entire spec file when it fails as a whole.
specFileRetries: 1, // The number of times to retry the entire spec file when it fails as a whole.

port: 4723, // default appium port
services: [
Expand Down
4 changes: 2 additions & 2 deletions apps/fluent-tester/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1290,7 +1290,7 @@ PODS:
- React-logger (= 0.74.7)
- React-perflogger (= 0.74.7)
- React-utils (= 0.74.7)
- ReactNativeHost (0.5.15):
- ReactNativeHost (0.5.16):
- DoubleConversion
- glog
- RCT-Folly (= 2024.01.01.00)
Expand Down Expand Up @@ -1569,7 +1569,7 @@ SPEC CHECKSUMS:
React-runtimescheduler: 7ae98c85d480214a491c40799501c94c7a188d73
React-utils: 269c55ca0a0a9d985fc8ab90898f7c1124784d73
ReactCommon: 345cad6a151c60c5d80bcc2005457fac2e079b82
ReactNativeHost: 91d43cc8ebaf158a27f8ae406a7e8b43ec823faa
ReactNativeHost: 4296c5d13fdcafb9cb53f2f3b6ab5e427ab9a6dd
ReactTestApp-DevSupport: 52ac76197e5accf579592aa3b9aa07fd0766f211
ReactTestApp-Resources: 41fbfc3cae89be49adf9cfa9d3a9954456c65ab1
RNSVG: d39a9be65c439dfb061955f7615f1f71a51ecede
Expand Down
4 changes: 2 additions & 2 deletions apps/fluent-tester/macos/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1223,7 +1223,7 @@ PODS:
- React-logger (= 0.74.30)
- React-perflogger (= 0.74.30)
- React-utils (= 0.74.30)
- ReactNativeHost (0.5.15):
- ReactNativeHost (0.5.16):
- DoubleConversion
- glog
- RCT-Folly (= 2024.01.01.00)
Expand Down Expand Up @@ -1516,7 +1516,7 @@ SPEC CHECKSUMS:
React-runtimescheduler: abda2da3b75a17017ba04f034deb9cf0eef16734
React-utils: ac5abf4d2d95d579be3b63fa44b46af2ca38544b
ReactCommon: 1eab570cb54edc279d28066475dbcf7e5b44c29e
ReactNativeHost: 91d43cc8ebaf158a27f8ae406a7e8b43ec823faa
ReactNativeHost: 4296c5d13fdcafb9cb53f2f3b6ab5e427ab9a6dd
ReactTestApp-DevSupport: 52ac76197e5accf579592aa3b9aa07fd0766f211
ReactTestApp-Resources: 3c8739a3e3ed26f67f8ab68f13102fb9591301c8
RNSVG: d39a9be65c439dfb061955f7615f1f71a51ecede
Expand Down
Loading
Loading