* Yarn

* Merge

* Fixing repo

* Update package

* Merge

* Removing change file

* Tests are running and succeeding, but the import still isn't working. I need to figure out how to import Platform from RN to choose the selector in BasePage

* Can't get WDIO to compile TS

* Updating WDIO to 6.5.0

* Updating Babel to 6.5.0 and integrating babel config. This should work, but it doesn't

* Making mac specific files

* Adding macos specific testing specs+page objects

* Fixing FocusZone spec for MacOS

* Reverting babel files back to original. The change did not work as I expected.

* Removing babel dependencies, not needed anymore

* Updating babel

* Nit changes

* Nit comments and removing unnecessary properties

* Nit comment

* Updating file name+import

* Nit changes to WebDriver macos config

* Adding MacOS E2E testing to CI pipeline

* Change files

* Updating file extensions of Windows specific files

* Removing Mac2 driver dependency from Win32/Windows package

* Removing unneeded package-locl files

* Fixing Appium logs

* Removing unnecessary dep from webdriver config

* Removing dep

* Removing dep

* Publishing MacOS build artifacts for CI

* testing ci

* Removing unnecessary step in CI Pipeline

* Updating Mac webdriver config file to take screenshots when test fails

* Testing CI

* Nit fix

* Reverting previous change

* Macos doesn't have browser.maximize funtionality

* Adding create a file functionality for reports

* Testing CI Pipeline - Seeing what directories are in /macos/ after E2E Test runs

* List contents of errorShots

* Reading contents of CI

* Testing CI

* Testing CI

* Finding applications folder

* Tesing CI for correct path

* Testing

* Test

* Testing CI

* Download tccutil command line tool

* Adding xcode to accessibility app permissions

* Updating download

* Attempting to disable SIP

* Removing unnecessary commands from CI

* Removing CI changes

* Nit styling

* Updating MacOS E2E Testubg documentation - How to run the tests locally

* Updating yarn.lock

* Nit: Spelling
This commit is contained in:
Samuel Freiberg 2021-12-16 16:11:01 -07:00 коммит произвёл GitHub
Родитель f7f98071b2
Коммит f293bf1103
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
86 изменённых файлов: 2931 добавлений и 295 удалений

Просмотреть файл

@ -7,16 +7,16 @@ steps:
# Copy Appium reports to FluentTesterDump
- task: CopyFiles@2
inputs:
sourceFolder: $(Build.SourcesDirectory)\apps\${{parameters.platform}}\reports\
targetFolder: $(Build.StagingDirectory)\E2E_${{parameters.applicationType}}_Dump
sourceFolder: $(Build.SourcesDirectory)/apps/${{parameters.platform}}/reports/
targetFolder: $(Build.StagingDirectory)/E2E_${{parameters.applicationType}}_Dump
displayName: "Copy Reports"
condition: and (succeededOrFailed(), eq(${{parameters.buildArtifacts}}, 'success'))
# Copy errorShots to FluentTesterDump
- task: CopyFiles@2
inputs:
sourceFolder: $(Build.SourcesDirectory)\apps\${{parameters.platform}}\errorShots\
targetFolder: $(Build.StagingDirectory)\E2E_${{parameters.applicationType}}_Dump
sourceFolder: $(Build.SourcesDirectory)/apps/${{parameters.platform}}/errorShots/
targetFolder: $(Build.StagingDirectory)/E2E_${{parameters.applicationType}}_Dump
displayName: "Copy tree dump screenshots"
condition: and (succeededOrFailed(), eq(${{parameters.buildArtifacts}}, 'success'))
@ -24,6 +24,6 @@ steps:
- task: PublishBuildArtifacts@1
inputs:
artifactName: E2E_${{parameters.applicationType}}_Dump
pathtoPublish: $(Build.StagingDirectory)\E2E_${{parameters.applicationType}}_Dump
pathtoPublish: $(Build.StagingDirectory)/E2E_${{parameters.applicationType}}_Dump
displayName: "Publish Artifact:E2E_${{parameters.applicationType}}_Dump"
condition: and (succeededOrFailed(), eq(${{parameters.buildArtifacts}}, 'success'))

Просмотреть файл

@ -62,13 +62,14 @@
"@types/react": "^17.0.2",
"@types/react-native": "^0.64.0",
"@uifabricshared/build-native": "^0.1.1",
"@wdio/appium-service": "5.18.2",
"@wdio/cli": "5.23.0",
"@wdio/jasmine-framework": "5.18.6",
"@wdio/local-runner": "5.23.0",
"@wdio/spec-reporter": "5.22.4",
"@wdio/sync": "5.20.1",
"appium": "1.17.1",
"@wdio/appium-service": "^6.5.0",
"@wdio/cli": "^6.5.0",
"@wdio/jasmine-framework": "^6.5.0",
"@wdio/local-runner": "^6.5.0",
"@wdio/spec-reporter": "^6.5.0",
"@wdio/sync": "^6.5.0",
"appium": "1.20.0",
"appium-mac2-driver": "0.14.1",
"metro-react-native-babel-preset": "^0.66.2",
"react": "17.0.1",
"react-native": "^0.64.3",
@ -81,7 +82,7 @@
"ts-node": "^8.10.1",
"tsconfig-paths": "^3.9.0",
"typescript": "3.8.3",
"webdriverio": "5.22.4"
"webdriverio": "^6.5.0"
},
"peerDependencies": {
"@office-iss/react-native-win32": "^0.64.8",

Просмотреть файл

@ -0,0 +1,34 @@
import {
BUTTON_TESTPAGE,
BUTTON_TEST_COMPONENT,
BUTTON_NO_A11Y_LABEL_COMPONENT,
HOMEPAGE_BUTTON_BUTTON,
} from '../../../FluentTester/TestComponents/Button/consts';
import { BasePage, By } from '../../common/BasePage.macos';
class ButtonPageObject extends BasePage {
/*****************************************/
/**************** Getters ****************/
/*****************************************/
get _testPage() {
return By(BUTTON_TESTPAGE);
}
get _pageName() {
return BUTTON_TESTPAGE;
}
get _primaryComponent() {
return By(BUTTON_TEST_COMPONENT);
}
get _secondaryComponent() {
return By(BUTTON_NO_A11Y_LABEL_COMPONENT);
}
get _pageButton() {
return By(HOMEPAGE_BUTTON_BUTTON);
}
}
export default new ButtonPageObject();

Просмотреть файл

@ -4,7 +4,7 @@ import {
BUTTON_NO_A11Y_LABEL_COMPONENT,
HOMEPAGE_BUTTON_BUTTON,
} from '../../../FluentTester/TestComponents/Button/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class ButtonPageObject extends BasePage {
/*****************************************/

Просмотреть файл

@ -0,0 +1,23 @@
import NavigateAppPage from '../../common/NavigateAppPage.macos';
import ButtonPageObject from '../pages/ButtonPageObject.macos';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';
// Before testing begins, allow up to 60 seconds for app to open
describe('Button Testing Initialization', function () {
it('Wait for app load', () => {
NavigateAppPage.waitForPageDisplayed(BOOT_APP_TIMEOUT);
expect(NavigateAppPage.isPageLoaded()).toBeTruthy();
});
it('Click and navigate to Button test page', () => {
/* Scroll to component test page button in scrollview if not already visible*/
ButtonPageObject.scrollToComponentButton();
ButtonPageObject.waitForButtonDisplayed(PAGE_TIMEOUT);
/* Click on component button to navigate to test page */
NavigateAppPage.clickAndGoToButtonPage();
ButtonPageObject.waitForPageDisplayed(PAGE_TIMEOUT);
expect(ButtonPageObject.isPageLoaded()).toBeTruthy();
});
});

Просмотреть файл

@ -1,6 +1,6 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import ButtonPageObject from '../pages/ButtonPageObject';
import { ComponentSelector } from '../../common/BasePage';
import { ComponentSelector } from '../../common/BasePage.win';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT, BUTTON_A11Y_ROLE } from '../../common/consts';
import { BUTTON_ACCESSIBILITY_LABEL, BUTTON_TEST_COMPONENT_LABEL } from '../../../FluentTester/TestComponents/Button/consts';

Просмотреть файл

@ -4,7 +4,7 @@ import {
BUTTONEXPERIMENTAL_NO_A11Y_LABEL_COMPONENT,
HOMEPAGE_BUTTON_BUTTONEXPERIMENTAL,
} from '../../../FluentTester/TestComponents/ButtonExperimental/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class ButtonExperimentalPageObject extends BasePage {
/*****************************************/

Просмотреть файл

@ -1,6 +1,6 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import ButtonExperimentalPageObject from '../pages/ButtonExperimentalPageObject';
import { ComponentSelector } from '../../common/BasePage';
import { ComponentSelector } from '../../common/BasePage.win';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT, BUTTON_A11Y_ROLE } from '../../common/consts';
import {
BUTTONEXPERIMENTAL_ACCESSIBILITY_LABEL,

Просмотреть файл

@ -0,0 +1,48 @@
import {
CALLOUT_TESTPAGE,
CALLOUT_TEST_COMPONENT,
HOMEPAGE_CALLOUT_BUTTON,
BUTTON_TO_OPEN_CALLOUT,
} from '../../../FluentTester/TestComponents/Callout/consts';
import { BasePage, By, COMPONENT_SCROLL_COORDINATES } from '../../common/BasePage.macos';
class CalloutPageObject extends BasePage {
/******************************************************************/
/**************** UI Element Interaction Methods ******************/
/******************************************************************/
didCalloutLoad(): boolean {
return this._primaryComponent.isDisplayed();
}
/* OVERRIDE: This must scroll to the button that opens the callout, not the callout (since it's not visible on load.) */
scrollToTestElement(): void {
while (!this._buttonToOpenCallout.isDisplayed()) {
driver.touchScroll(COMPONENT_SCROLL_COORDINATES.x, COMPONENT_SCROLL_COORDINATES.y, this._testPage.elementId);
}
}
/*****************************************/
/**************** Getters ****************/
/*****************************************/
get _testPage() {
return By(CALLOUT_TESTPAGE);
}
get _pageName() {
return CALLOUT_TESTPAGE;
}
get _primaryComponent() {
return By(CALLOUT_TEST_COMPONENT);
}
get _pageButton() {
return By(HOMEPAGE_CALLOUT_BUTTON);
}
get _buttonToOpenCallout() {
return By(BUTTON_TO_OPEN_CALLOUT);
}
}
export default new CalloutPageObject();

Просмотреть файл

@ -4,7 +4,7 @@ import {
HOMEPAGE_CALLOUT_BUTTON,
BUTTON_TO_OPEN_CALLOUT,
} from '../../../FluentTester/TestComponents/Callout/consts';
import { BasePage, By, COMPONENT_SCROLL_COORDINATES } from '../../common/BasePage';
import { BasePage, By, COMPONENT_SCROLL_COORDINATES } from '../../common/BasePage.win';
class CalloutPageObject extends BasePage {
/******************************************************************/

Просмотреть файл

@ -1,4 +1,4 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import CalloutPageObject from '../pages/CalloutPageObject.win';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';

Просмотреть файл

@ -0,0 +1,54 @@
import {
CHECKBOX_TESTPAGE,
CHECKBOX_TEST_COMPONENT,
CHECKBOX_NO_A11Y_LABEL_COMPONENT,
HOMEPAGE_CHECKBOX_BUTTON,
} from '../../../FluentTester/TestComponents/Checkbox/consts';
import { BasePage, By } from '../../common/BasePage.macos';
class CheckboxPageObject extends BasePage {
/******************************************************************/
/**************** UI Element Interaction Methods ******************/
/******************************************************************/
isCheckboxChecked(): boolean {
return this._primaryComponent.isSelected();
}
waitForCheckboxUnchecked(timeout?: number): void {
browser.waitUntil(
() => {
return !this.isCheckboxChecked();
},
{
timeout: timeout ?? this.waitForPageTimeout,
timeoutMsg: 'The onPress() callback for ' + this._pageName + ' did not fire correctly.',
interval: 1000,
},
);
}
/*****************************************/
/**************** Getters ****************/
/*****************************************/
get _testPage() {
return By(CHECKBOX_TESTPAGE);
}
get _pageName() {
return CHECKBOX_TESTPAGE;
}
get _primaryComponent() {
return By(CHECKBOX_TEST_COMPONENT);
}
get _secondaryComponent() {
return By(CHECKBOX_NO_A11Y_LABEL_COMPONENT);
}
get _pageButton() {
return By(HOMEPAGE_CHECKBOX_BUTTON);
}
}
export default new CheckboxPageObject();

Просмотреть файл

@ -4,7 +4,7 @@ import {
CHECKBOX_NO_A11Y_LABEL_COMPONENT,
HOMEPAGE_CHECKBOX_BUTTON,
} from '../../../FluentTester/TestComponents/Checkbox/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class CheckboxPageObject extends BasePage {
/******************************************************************/
@ -19,9 +19,11 @@ class CheckboxPageObject extends BasePage {
() => {
return !this.isCheckboxChecked();
},
timeout ?? this.waitForPageTimeout,
'The onPress() callback for ' + this._pageName + ' did not fire correctly.',
2000,
{
timeout: timeout ?? this.waitForPageTimeout,
timeoutMsg: 'The onPress() callback for ' + this._pageName + ' did not fire correctly.',
interval: 1000,
},
);
}

Просмотреть файл

@ -0,0 +1,22 @@
import NavigateAppPage from '../../common/NavigateAppPage.macos';
import CheckboxPageObject from '../pages/CheckboxPageObject.macos';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';
describe('Checkbox Testing Initialization', () => {
it('Wait for app load', () => {
NavigateAppPage.waitForPageDisplayed(BOOT_APP_TIMEOUT);
expect(NavigateAppPage.isPageLoaded()).toBeTruthy();
});
it('Click and navigate to Checkbox test page', () => {
/* Scroll to component test page button in scrollview if not already visible*/
CheckboxPageObject.scrollToComponentButton();
CheckboxPageObject.waitForButtonDisplayed(PAGE_TIMEOUT);
/* Click on component button to navigate to test page */
NavigateAppPage.clickAndGoToCheckboxPage();
CheckboxPageObject.waitForPageDisplayed(PAGE_TIMEOUT);
expect(CheckboxPageObject.isPageLoaded()).toBeTruthy();
});
});

Просмотреть файл

@ -1,6 +1,6 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import CheckboxPageObject from '../pages/CheckboxPageObject';
import { ComponentSelector } from '../../common/BasePage';
import { ComponentSelector } from '../../common/BasePage.win';
import { CHECKBOX_TEST_COMPONENT_LABEL, CHECKBOX_ACCESSIBILITY_LABEL } from '../../../FluentTester/TestComponents/Checkbox/consts';
import { CHECKBOX_A11Y_ROLE, PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';

Просмотреть файл

@ -3,7 +3,7 @@ import {
CONTEXTUALMENU_TEST_COMPONENT,
HOMEPAGE_CONTEXTUALMENU_BUTTON,
} from '../../../FluentTester/TestComponents/ContextualMenu/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class ContextualMenuPageObject extends BasePage {
/*****************************************/

Просмотреть файл

@ -1,4 +1,4 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import ContextualMenuPageObjectObject from '../pages/ContextualMenuPageObject.win';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';

Просмотреть файл

@ -3,7 +3,7 @@ import {
FOCUSTRAPZONE_TEST_COMPONENT,
HOMEPAGE_FOCUSTRAPZONE_BUTTON,
} from '../../../FluentTester/TestComponents/FocusTrapZone/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class FocusTrapZonePageObject extends BasePage {
// OVERRIDE: We use isExisting() here instead of isDisplayed() because FocusTrapZone does not have any UI to it, it's simply

Просмотреть файл

@ -1,4 +1,4 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import FocusTrapZonePageObject from '../pages/FocusTrapZonePageObject.win';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';

Просмотреть файл

@ -0,0 +1,36 @@
import {
FOCUSZONE_TESTPAGE,
FOCUSZONE_TEST_COMPONENT,
HOMEPAGE_FOCUSZONE_BUTTON,
} from '../../../FluentTester/TestComponents/FocusZone/consts';
import { BasePage, By } from '../../common/BasePage.macos';
class FocusZonePageObject extends BasePage {
// OVERRIDE: We use isExisting() here instead of isDisplayed() because FocusZone does not have any UI to it, it's simply
// a wrapper that adds keyboard focus functionality
waitForPrimaryElementDisplayed(timeout?: number): void {
const errorMsg = 'The FocusZone UI Element did not load correctly. Please see logs.';
this.waitForCondition(() => this._primaryComponent.isExisting(), errorMsg, timeout);
}
/*****************************************/
/**************** Getters ****************/
/*****************************************/
get _testPage() {
return By(FOCUSZONE_TESTPAGE);
}
get _pageName() {
return FOCUSZONE_TESTPAGE;
}
get _primaryComponent() {
return By(FOCUSZONE_TEST_COMPONENT);
}
get _pageButton() {
return By(HOMEPAGE_FOCUSZONE_BUTTON);
}
}
export default new FocusZonePageObject();

Просмотреть файл

@ -3,7 +3,7 @@ import {
FOCUSZONE_TEST_COMPONENT,
HOMEPAGE_FOCUSZONE_BUTTON,
} from '../../../FluentTester/TestComponents/FocusZone/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class FocusZonePageObject extends BasePage {
// OVERRIDE: We use isExisting() here instead of isDisplayed() because FocusZone does not have any UI to it, it's simply

Просмотреть файл

@ -0,0 +1,23 @@
import NavigateAppPage from '../../common/NavigateAppPage.macos';
import FocusZonePageObject from '../pages/FocusZonePageObject.macos';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';
// Before testing begins, allow up to 60 seconds for app to open
describe('FocusZone Testing Initialization', function () {
it('Wait for app load', () => {
NavigateAppPage.waitForPageDisplayed(BOOT_APP_TIMEOUT);
expect(NavigateAppPage.isPageLoaded()).toBeTruthy();
});
it('Click and navigate to FocusZone test page', () => {
/* Scroll to component test page button in scrollview if not already visible*/
FocusZonePageObject.scrollToComponentButton();
FocusZonePageObject.waitForButtonDisplayed(PAGE_TIMEOUT);
/* Click on component button to navigate to test page */
NavigateAppPage.clickAndGoToFocusZonePage();
FocusZonePageObject.waitForPageDisplayed(PAGE_TIMEOUT);
expect(FocusZonePageObject.isPageLoaded()).toBeTruthy();
});
});

Просмотреть файл

@ -1,4 +1,4 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import FocusZonePageObject from '../pages/FocusZonePageObject.win';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';

Просмотреть файл

@ -0,0 +1,34 @@
import {
ICON_TESTPAGE,
ICON_TEST_COMPONENT,
HOMEPAGE_ICON_BUTTON,
ICON_NO_A11Y_LABEL_COMPONENT,
} from '../../../FluentTester/TestComponents/Icon/consts';
import { BasePage, By } from '../../common/BasePage.macos';
class IconPageObject extends BasePage {
/*****************************************/
/**************** Getters ****************/
/*****************************************/
get _testPage() {
return By(ICON_TESTPAGE);
}
get _pageName() {
return ICON_TESTPAGE;
}
get _primaryComponent() {
return By(ICON_TEST_COMPONENT);
}
get _secondaryComponent() {
return By(ICON_NO_A11Y_LABEL_COMPONENT);
}
get _pageButton() {
return By(HOMEPAGE_ICON_BUTTON);
}
}
export default new IconPageObject();

Просмотреть файл

@ -4,7 +4,7 @@ import {
HOMEPAGE_ICON_BUTTON,
ICON_NO_A11Y_LABEL_COMPONENT,
} from '../../../FluentTester/TestComponents/Icon/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class IconPageObject extends BasePage {
/*****************************************/

Просмотреть файл

@ -0,0 +1,23 @@
import NavigateAppPage from '../../common/NavigateAppPage.macos';
import IconPageObject from '../pages/IconPageObject.macos';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';
// Before testing begins, allow up to 60 seconds for app to open
describe('Icon Testing Initialization', function () {
it('Wait for app load', () => {
NavigateAppPage.waitForPageDisplayed(BOOT_APP_TIMEOUT);
expect(NavigateAppPage.isPageLoaded()).toBeTruthy();
});
it('Click and navigate to Icon test page', () => {
/* Scroll to component test page button in scrollview if not already visible*/
IconPageObject.scrollToComponentButton();
IconPageObject.waitForButtonDisplayed(PAGE_TIMEOUT);
/* Click on component button to navigate to test page */
NavigateAppPage.clickAndGoToIconPage();
IconPageObject.waitForPageDisplayed(PAGE_TIMEOUT);
expect(IconPageObject.isPageLoaded()).toBeTruthy();
});
});

Просмотреть файл

@ -1,4 +1,4 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import IconPageObject from '../pages/IconPageObject.win';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';

Просмотреть файл

@ -0,0 +1,34 @@
import {
LINK_TESTPAGE,
LINK_TEST_COMPONENT,
HOMEPAGE_LINK_BUTTON,
LINK_NO_A11Y_LABEL_COMPONENT,
} from '../../../FluentTester/TestComponents/Link/consts';
import { BasePage, By } from '../../common/BasePage.macos';
class LinkPageObject extends BasePage {
/*****************************************/
/**************** Getters ****************/
/*****************************************/
get _testPage() {
return By(LINK_TESTPAGE);
}
get _pageName() {
return LINK_TESTPAGE;
}
get _primaryComponent() {
return By(LINK_TEST_COMPONENT);
}
get _secondaryComponent() {
return By(LINK_NO_A11Y_LABEL_COMPONENT);
}
get _pageButton() {
return By(HOMEPAGE_LINK_BUTTON);
}
}
export default new LinkPageObject();

Просмотреть файл

@ -4,7 +4,7 @@ import {
HOMEPAGE_LINK_BUTTON,
LINK_NO_A11Y_LABEL_COMPONENT,
} from '../../../FluentTester/TestComponents/Link/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class LinkPageObject extends BasePage {
/*****************************************/

Просмотреть файл

@ -0,0 +1,23 @@
import NavigateAppPage from '../../common/NavigateAppPage.macos';
import LinkPageObject from '../pages/LinkPageObject.macos';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';
// Before testing begins, allow up to 60 seconds for app to open
describe('Link Testing Initialization', function () {
it('Wait for app load', () => {
NavigateAppPage.waitForPageDisplayed(BOOT_APP_TIMEOUT);
expect(NavigateAppPage.isPageLoaded()).toBeTruthy();
});
it('Click and navigate to Link test page', () => {
/* Scroll to component test page button in scrollview if not already visible*/
LinkPageObject.scrollToComponentButton();
LinkPageObject.waitForButtonDisplayed(PAGE_TIMEOUT);
/* Click on component button to navigate to test page */
NavigateAppPage.clickAndGoToLinkPage();
LinkPageObject.waitForPageDisplayed(PAGE_TIMEOUT);
expect(LinkPageObject.isPageLoaded()).toBeTruthy();
});
});

Просмотреть файл

@ -1,6 +1,6 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import LinkPageObject from '../pages/LinkPageObject';
import { ComponentSelector } from '../../common/BasePage';
import { ComponentSelector } from '../../common/BasePage.win';
import { LINK_ACCESSIBILITY_LABEL } from '../../../FluentTester/TestComponents/Link/consts';
import { LINK_A11Y_ROLE, PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';

Просмотреть файл

@ -4,7 +4,7 @@ import {
HOMEPAGE_MENU_BUTTON,
MENU_BUTTON_NO_A11Y_LABEL_COMPONENT,
} from '../../../FluentTester/TestComponents/MenuButton/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class MenuButtonPageObject extends BasePage {
/*****************************************/

Просмотреть файл

@ -1,8 +1,8 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import MenuButtonPageObject from '../pages/MenuButtonPageObject.win';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT, MENUBUTTON_A11Y_ROLE } from '../../common/consts';
import { MENU_BUTTON_ACCESSIBILITY_LABEL, MENU_BUTTON_TEST_COMPONENT_LABEL } from '../../../FluentTester/TestComponents/MenuButton/consts';
import { ComponentSelector } from '../../common/BasePage';
import { ComponentSelector } from '../../common/BasePage.win';
// Before testing begins, allow up to 60 seconds for app to open
describe('MenuButton Testing Initialization', function () {

Просмотреть файл

@ -0,0 +1,25 @@
import { PERSONA_TESTPAGE, PERSONA_TEST_COMPONENT, HOMEPAGE_PERSONA_BUTTON } from '../../../FluentTester/TestComponents/Persona/consts';
import { BasePage, By } from '../../common/BasePage.macos';
class PersonaPageObject extends BasePage {
/*****************************************/
/**************** Getters ****************/
/*****************************************/
get _testPage() {
return By(PERSONA_TESTPAGE);
}
get _pageName() {
return PERSONA_TESTPAGE;
}
get _primaryComponent() {
return By(PERSONA_TEST_COMPONENT);
}
get _pageButton() {
return By(HOMEPAGE_PERSONA_BUTTON);
}
}
export default new PersonaPageObject();

Просмотреть файл

@ -1,5 +1,5 @@
import { PERSONA_TESTPAGE, PERSONA_TEST_COMPONENT, HOMEPAGE_PERSONA_BUTTON } from '../../../FluentTester/TestComponents/Persona/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class PersonaPageObject extends BasePage {
/*****************************************/

Просмотреть файл

@ -0,0 +1,23 @@
import NavigateAppPage from '../../common/NavigateAppPage.macos';
import PersonaPageObject from '../pages/PersonaPageObject.macos';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';
// Before testing begins, allow up to 60 seconds for app to open
describe('Persona Testing Initialization', function () {
it('Wait for app load', () => {
NavigateAppPage.waitForPageDisplayed(BOOT_APP_TIMEOUT);
expect(NavigateAppPage.isPageLoaded()).toBeTruthy();
});
it('Click and navigate to Persona test page', () => {
/* Scroll to component test page button in scrollview if not already visible*/
PersonaPageObject.scrollToComponentButton();
PersonaPageObject.waitForButtonDisplayed(PAGE_TIMEOUT);
/* Click on component button to navigate to test page */
NavigateAppPage.clickAndGoToPersonaPage();
PersonaPageObject.waitForPageDisplayed(PAGE_TIMEOUT);
expect(PersonaPageObject.isPageLoaded()).toBeTruthy();
});
});

Просмотреть файл

@ -1,4 +1,4 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import PersonaPageObject from '../pages/PersonaPageObject.win';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';

Просмотреть файл

@ -0,0 +1,29 @@
import {
PERSONACOIN_TESTPAGE,
PERSONACOIN_TEST_COMPONENT,
HOMEPAGE_PERSONACOIN_BUTTON,
} from '../../../FluentTester/TestComponents/PersonaCoin/consts';
import { BasePage, By } from '../../common/BasePage.macos';
class PersonaCoinPageObject extends BasePage {
/*****************************************/
/**************** Getters ****************/
/*****************************************/
get _testPage() {
return By(PERSONACOIN_TESTPAGE);
}
get _pageName() {
return PERSONACOIN_TESTPAGE;
}
get _primaryComponent() {
return By(PERSONACOIN_TEST_COMPONENT);
}
get _pageButton() {
return By(HOMEPAGE_PERSONACOIN_BUTTON);
}
}
export default new PersonaCoinPageObject();

Просмотреть файл

@ -3,7 +3,7 @@ import {
PERSONACOIN_TEST_COMPONENT,
HOMEPAGE_PERSONACOIN_BUTTON,
} from '../../../FluentTester/TestComponents/PersonaCoin/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class PersonaCoinPageObject extends BasePage {
/*****************************************/

Просмотреть файл

@ -0,0 +1,23 @@
import NavigateAppPage from '../../common/NavigateAppPage.macos';
import PersonaCoinPageObject from '../pages/PersonaCoinPageObject.macos';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';
// Before testing begins, allow up to 60 seconds for app to open
describe('PersonaCoin Testing Initialization', function () {
it('Wait for app load', () => {
NavigateAppPage.waitForPageDisplayed(BOOT_APP_TIMEOUT);
expect(NavigateAppPage.isPageLoaded()).toBeTruthy();
});
it('Click and navigate to PersonaCoin test page', () => {
/* Scroll to component test page button in scrollview if not already visible*/
PersonaCoinPageObject.scrollToComponentButton();
PersonaCoinPageObject.waitForButtonDisplayed(PAGE_TIMEOUT);
/* Click on component button to navigate to test page */
NavigateAppPage.clickAndGoToPersonaCoinPage();
PersonaCoinPageObject.waitForPageDisplayed(PAGE_TIMEOUT);
expect(PersonaCoinPageObject.isPageLoaded()).toBeTruthy();
});
});

Просмотреть файл

@ -1,4 +1,4 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import PersonaCoinPageObject from '../pages/PersonaCoinPageObject.win';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';

Просмотреть файл

@ -0,0 +1,29 @@
import {
PRESSABLE_TESTPAGE,
PRESSABLE_TEST_COMPONENT,
HOMEPAGE_PRESSABLE_BUTTON,
} from '../../../FluentTester/TestComponents/Pressable/consts';
import { BasePage, By } from '../../common/BasePage.macos';
class PressablePageObject extends BasePage {
/*****************************************/
/**************** Getters ****************/
/*****************************************/
get _testPage() {
return By(PRESSABLE_TESTPAGE);
}
get _pageName() {
return PRESSABLE_TESTPAGE;
}
get _primaryComponent() {
return By(PRESSABLE_TEST_COMPONENT);
}
get _pageButton() {
return By(HOMEPAGE_PRESSABLE_BUTTON);
}
}
export default new PressablePageObject();

Просмотреть файл

@ -3,7 +3,7 @@ import {
PRESSABLE_TEST_COMPONENT,
HOMEPAGE_PRESSABLE_BUTTON,
} from '../../../FluentTester/TestComponents/Pressable/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class PressablePageObject extends BasePage {
/*****************************************/

Просмотреть файл

@ -0,0 +1,23 @@
import NavigateAppPage from '../../common/NavigateAppPage.macos';
import PressablePageObject from '../pages/PressablePageObject.macos';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';
// Before testing begins, allow up to 60 seconds for app to open
describe('Pressable Testing Initialization', function () {
it('Wait for app load', () => {
NavigateAppPage.waitForPageDisplayed(BOOT_APP_TIMEOUT);
expect(NavigateAppPage.isPageLoaded()).toBeTruthy();
});
it('Click and navigate to Pressable test page', () => {
/* Scroll to component test page button in scrollview if not already visible*/
PressablePageObject.scrollToComponentButton();
PressablePageObject.waitForButtonDisplayed(PAGE_TIMEOUT);
/* Click on component button to navigate to test page */
NavigateAppPage.clickAndGoToPressablePage();
PressablePageObject.waitForPageDisplayed(PAGE_TIMEOUT);
expect(PressablePageObject.isPageLoaded()).toBeTruthy();
});
});

Просмотреть файл

@ -1,4 +1,4 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import PressablePageObject from '../pages/PressablePageObject.win';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';

Просмотреть файл

@ -1,20 +1,27 @@
# E2E Testing Overview
## Prerequisites
## Win32/UWP Prerequisites
- [Node.js](https://nodejs.org/en/download/) - Version 10.19 or higher.
- [React Native Windows Development Dependencies](https://microsoft.github.io/react-native-windows/docs/rnw-dependencies)
- **NOTE:** Please make sure you grab all of the items listed there and the appropriate versions.
- [WinAppDriver](https://github.com/microsoft/WinAppDriver) - Version 1.1
- Enable [_Developer Mode_](https://docs.microsoft.com/en-us/windows/uwp/get-started/enable-your-device-for-development) in Windows settings
- [Java 1.8](https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html) (Optional) - Used for generating in-depth after-action reports. More information in "Debugging E2E Failures" section below.
- [Allure Command-Line](https://www.npmjs.com/package/allure-commandline) (Optional) - Used for creating in-depth reporting.
- `npm install -g allure-commandline`
### UWP Additional Prerequisites
- [UWP Prerequisites](https://github.com/microsoft/fluentui-react-native/blob/master/apps/windows/README.md)
## MacOS Prerequisites
- MacOS 10.15 or later
- XCode 12 or later should be installed
- XCode Helper app should be enabled for Accessibility access. The app itself is usually found at: _/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Agents/Xcode Helper.app_.
In order to enable Accessibility access, simply open the parent folder in finder:
_open /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Xcode/Agents/_
and drag & drop the **XCode Helper** app to **Security & Privacy -> Privacy -> Accessibility** list of your **System Preferences**. This action must only be done once.
## E2E Project Structure
- E2E - The root E2E testing folder containing test components and their respective platform-specific page objects and spec documents.
@ -46,6 +53,20 @@
_Note: It could take up to a minute to load the test app with WebDriverIO, don't panic, the tests will run :)_
## MacOS Steps
1. Follow step #1 from "Win32 Steps" section above.
2. POD Install
- C:\repo\fluentui-react-native> `cd apps\macos\src`
- C:\repo\fluentui-react-native\apps\macos\src> `pod install`
3. Start the server
- C:\repo\fluentui-react-native> `cd apps\macos`
- C:\repo\fluentui-react-native\apps\macos> `yarn start`
4. Open a new command prompt and run the E2E tests
- C:\repo\fluentui-react-native\apps\macos> `yarn e2etest`
_Note: It could take up to a minute to load the test app with WebDriverIO, don't panic, the tests will run :)_
# Authoring E2E Test
Testing is split-up on a **per-component** basis. Each component's testing story is made up of two parts - a **Page Object** and a **Spec Document**.

Просмотреть файл

@ -0,0 +1,70 @@
import {
RADIOGROUP_TESTPAGE,
RADIOGROUP_TEST_COMPONENT,
RADIOGROUP_NO_A11Y_LABEL_COMPONENT,
RADIOBUTTON_TEST_COMPONENT,
HOMEPAGE_RADIOGROUP_BUTTON,
RADIOBUTTON_NO_A11Y_LABEL_COMPONENT,
} from '../../../FluentTester/TestComponents/RadioGroup/consts';
import { BasePage, By } from '../../common/BasePage.macos';
export const enum RadioButtonSelector {
Primary = 0, // this._primaryComponent
Secondary, // this._secondaryComponent
}
class RadioGroupPage extends BasePage {
/******************************************************************/
/**************** UI Element Interaction Methods ******************/
/******************************************************************/
// Get RadioButton's accessibilityLabel
getRBAccessibilityLabel(radioButtonSelector: RadioButtonSelector): string {
switch (radioButtonSelector) {
case RadioButtonSelector.Primary:
return this._radioButton.getAttribute('Name');
case RadioButtonSelector.Secondary:
return this._secondRadioButton.getAttribute('Name');
}
}
getRadioButtonAccesibilityRole(): string {
return this._radioButton.getAttribute('ControlType');
}
/*****************************************/
/**************** Getters ****************/
/*****************************************/
get _testPage() {
return By(RADIOGROUP_TESTPAGE);
}
get _pageName() {
return RADIOGROUP_TESTPAGE;
}
get _primaryComponent() {
return By(RADIOGROUP_TEST_COMPONENT);
}
get _secondaryComponent() {
return By(RADIOGROUP_NO_A11Y_LABEL_COMPONENT);
}
get _pageButton() {
return By(HOMEPAGE_RADIOGROUP_BUTTON);
}
/***************/
/* RadioButton *
/**************/
get _radioButton() {
return By(RADIOBUTTON_TEST_COMPONENT);
}
get _secondRadioButton() {
return By(RADIOBUTTON_NO_A11Y_LABEL_COMPONENT);
}
}
export default new RadioGroupPage();

Просмотреть файл

@ -6,7 +6,7 @@ import {
HOMEPAGE_RADIOGROUP_BUTTON,
RADIOBUTTON_NO_A11Y_LABEL_COMPONENT,
} from '../../../FluentTester/TestComponents/RadioGroup/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
export const enum RadioButtonSelector {
Primary = 0, // this._primaryComponent

Просмотреть файл

@ -0,0 +1,23 @@
import NavigateAppPage from '../../common/NavigateAppPage.macos';
import RadioGroupPageObject from '../pages/RadioGroupPageObject.macos';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';
// Before testing begins, allow up to 60 seconds for app to open
describe('RadioGroup/RadioButton Testing Initialization', function () {
it('Wait for app load', () => {
NavigateAppPage.waitForPageDisplayed(BOOT_APP_TIMEOUT);
expect(NavigateAppPage.isPageLoaded()).toBeTruthy();
});
it('Click and navigate to RadioGroup test page', () => {
/* Scroll to component test page button in scrollview if not already visible*/
RadioGroupPageObject.scrollToComponentButton();
RadioGroupPageObject.waitForButtonDisplayed(PAGE_TIMEOUT);
/* Click on component button to navigate to test page */
NavigateAppPage.clickAndGoToRadioGroupPage();
RadioGroupPageObject.waitForPageDisplayed(PAGE_TIMEOUT);
expect(RadioGroupPageObject.isPageLoaded()).toBeTruthy();
});
});

Просмотреть файл

@ -1,6 +1,6 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import RadioGroupPageObject, { RadioButtonSelector } from '../pages/RadioGroupPageObject.win';
import { ComponentSelector } from '../../common/BasePage';
import { ComponentSelector } from '../../common/BasePage.win';
import { RADIOBUTTON_A11Y_ROLE, RADIOGROUP_A11Y_ROLE, PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';
import {
RADIOGROUP_ACCESSIBILITY_LABEL,

Просмотреть файл

@ -0,0 +1,29 @@
import {
SEPARATOR_TESTPAGE,
SEPARATOR_TEST_COMPONENT,
HOMEPAGE_SEPARATOR_BUTTON,
} from '../../../FluentTester/TestComponents/Separator/consts';
import { BasePage, By } from '../../common/BasePage.macos';
class SeparatorPageObject extends BasePage {
/*****************************************/
/**************** Getters ****************/
/*****************************************/
get _testPage() {
return By(SEPARATOR_TESTPAGE);
}
get _pageName() {
return SEPARATOR_TESTPAGE;
}
get _primaryComponent() {
return By(SEPARATOR_TEST_COMPONENT);
}
get _pageButton() {
return By(HOMEPAGE_SEPARATOR_BUTTON);
}
}
export default new SeparatorPageObject();

Просмотреть файл

@ -3,7 +3,7 @@ import {
SEPARATOR_TEST_COMPONENT,
HOMEPAGE_SEPARATOR_BUTTON,
} from '../../../FluentTester/TestComponents/Separator/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class SeparatorPageObject extends BasePage {
/*****************************************/

Просмотреть файл

@ -0,0 +1,23 @@
import NavigateAppPage from '../../common/NavigateAppPage.macos';
import SeparatorPageObject from '../pages/SeparatorPageObject.macos';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';
// Before testing begins, allow up to 60 seconds for app to open
describe('Separator Testing Initialization', function () {
it('Wait for app load', () => {
NavigateAppPage.waitForPageDisplayed(BOOT_APP_TIMEOUT);
expect(NavigateAppPage.isPageLoaded()).toBeTruthy();
});
it('Click and navigate to Separator test page', () => {
/* Scroll to component test page button in scrollview if not already visible*/
SeparatorPageObject.scrollToComponentButton();
SeparatorPageObject.waitForButtonDisplayed(PAGE_TIMEOUT);
/* Click on component button to navigate to test page */
NavigateAppPage.clickAndGoToSeparatorPage();
SeparatorPageObject.waitForPageDisplayed(PAGE_TIMEOUT);
expect(SeparatorPageObject.isPageLoaded()).toBeTruthy();
});
});

Просмотреть файл

@ -1,4 +1,4 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import SeparatorPageObject from '../pages/SeparatorPageObject.win';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';

Просмотреть файл

@ -0,0 +1,25 @@
import { SVG_TESTPAGE, SVG_TEST_COMPONENT, HOMEPAGE_SVG_BUTTON } from '../../../FluentTester/TestComponents/Svg/consts';
import { BasePage, By } from '../../common/BasePage.macos';
class SvgPageObject extends BasePage {
/*****************************************/
/**************** Getters ****************/
/*****************************************/
get _testPage() {
return By(SVG_TESTPAGE);
}
get _pageName() {
return SVG_TESTPAGE;
}
get _primaryComponent() {
return By(SVG_TEST_COMPONENT);
}
get _pageButton() {
return By(HOMEPAGE_SVG_BUTTON);
}
}
export default new SvgPageObject();

Просмотреть файл

@ -1,5 +1,5 @@
import { SVG_TESTPAGE, SVG_TEST_COMPONENT, HOMEPAGE_SVG_BUTTON } from '../../../FluentTester/TestComponents/Svg/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class SvgPageObject extends BasePage {
/*****************************************/

Просмотреть файл

@ -0,0 +1,23 @@
import NavigateAppPage from '../../common/NavigateAppPage.macos';
import SvgPageObject from '../pages/SvgPageObject.macos';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';
// Before testing begins, allow up to 60 seconds for app to open
describe('Svg Testing Initialization', function () {
it('Wait for app load', () => {
NavigateAppPage.waitForPageDisplayed(BOOT_APP_TIMEOUT);
expect(NavigateAppPage.isPageLoaded()).toBeTruthy();
});
it('Click and navigate to Svg test page', () => {
/* Scroll to component test page button in scrollview if not already visible*/
SvgPageObject.scrollToComponentButton();
SvgPageObject.waitForButtonDisplayed(PAGE_TIMEOUT);
/* Click on component button to navigate to test page */
NavigateAppPage.clickAndGoToSvgPage();
SvgPageObject.waitForPageDisplayed(PAGE_TIMEOUT);
expect(SvgPageObject.isPageLoaded()).toBeTruthy();
});
});

Просмотреть файл

@ -1,4 +1,4 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import SvgPageObject from '../pages/SvgPageObject.win';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';

Просмотреть файл

@ -0,0 +1,44 @@
import {
TABS_TESTPAGE,
TABS_TEST_COMPONENT,
TABS_ITEM_TEST_COMPONENT,
HOMEPAGE_TABS_BUTTON,
} from '../../../FluentTester/TestComponents/Tabs/consts';
import { BasePage, By } from '../../common/BasePage.macos';
class TabsPageObject extends BasePage {
/******************************************************************/
/**************** UI Element Interaction Methods ******************/
/******************************************************************/
getTabItemAccesibilityRole(): string {
return this._tabItem.getAttribute('ControlType');
}
/*****************************************/
/**************** Getters ****************/
/*****************************************/
get _testPage() {
return By(TABS_TESTPAGE);
}
get _pageName() {
return TABS_TESTPAGE;
}
get _primaryComponent() {
return By(TABS_TEST_COMPONENT);
}
get _pageButton() {
return By(HOMEPAGE_TABS_BUTTON);
}
/***********/
/* TabItem *
/***********/
get _tabItem() {
return By(TABS_ITEM_TEST_COMPONENT);
}
}
export default new TabsPageObject();

Просмотреть файл

@ -4,7 +4,7 @@ import {
TABS_ITEM_TEST_COMPONENT,
HOMEPAGE_TABS_BUTTON,
} from '../../../FluentTester/TestComponents/Tabs/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class TabsPageObject extends BasePage {
/******************************************************************/

Просмотреть файл

@ -0,0 +1,23 @@
import NavigateAppPage from '../../common/NavigateAppPage.macos';
import TabsPageObject from '../pages/TabsPageObject.macos';
import { BOOT_APP_TIMEOUT, PAGE_TIMEOUT } from '../../common/consts';
// Before testing begins, allow up to 60 seconds for app to open
describe('Tabs Testing Initialization', function () {
it('Wait for app load', () => {
NavigateAppPage.waitForPageDisplayed(BOOT_APP_TIMEOUT);
expect(NavigateAppPage.isPageLoaded()).toBeTruthy();
});
it('Click and navigate to Tabs test page', () => {
/* Scroll to component test page button in scrollview if not already visible*/
TabsPageObject.scrollToComponentButton();
TabsPageObject.waitForButtonDisplayed(PAGE_TIMEOUT);
/* Click on component button to navigate to test page */
NavigateAppPage.clickAndGoToTabsPage();
TabsPageObject.waitForPageDisplayed(PAGE_TIMEOUT);
expect(TabsPageObject.isPageLoaded()).toBeTruthy();
});
});

Просмотреть файл

@ -1,4 +1,4 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import TabsPageObject from '../pages/TabsPageObject.win';
import { TAB_A11Y_ROLE, BOOT_APP_TIMEOUT, PAGE_TIMEOUT, TABITEM_A11Y_ROLE } from '../../common/consts';

Просмотреть файл

@ -0,0 +1,44 @@
import {
EXPERIMENTAL_TABS_ITEM_TEST_COMPONENT,
EXPERIMENTAL_TABS_TESTPAGE,
EXPERIMENTAL_TABS_TEST_COMPONENT,
HOMEPAGE_EXPERIMENTAL_TABS_BUTTON,
} from '../../../FluentTester/TestComponents/TabsExperimental/consts';
import { BasePage, By } from '../../common/BasePage.macos';
class ExperimentalTabsPageObject extends BasePage {
/******************************************************************/
/**************** UI Element Interaction Methods ******************/
/******************************************************************/
getTabItemAccesibilityRole(): string {
return this._tabItem.getAttribute('ControlType');
}
/*****************************************/
/**************** Getters ****************/
/*****************************************/
get _testPage() {
return By(EXPERIMENTAL_TABS_TESTPAGE);
}
get _pageName() {
return EXPERIMENTAL_TABS_TESTPAGE;
}
get _primaryComponent() {
return By(EXPERIMENTAL_TABS_TEST_COMPONENT);
}
get _pageButton() {
return By(HOMEPAGE_EXPERIMENTAL_TABS_BUTTON);
}
/***********/
/* TabItem *
/***********/
get _tabItem() {
return By(EXPERIMENTAL_TABS_ITEM_TEST_COMPONENT);
}
}
export default new ExperimentalTabsPageObject();

Просмотреть файл

@ -4,7 +4,7 @@ import {
EXPERIMENTAL_TABS_TEST_COMPONENT,
HOMEPAGE_EXPERIMENTAL_TABS_BUTTON,
} from '../../../FluentTester/TestComponents/TabsExperimental/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class ExperimentalTabsPageObject extends BasePage {
/******************************************************************/

Просмотреть файл

@ -0,0 +1,23 @@
import NavigateAppPage from '../../common/NavigateAppPage.macos';
import ExperimentalTabsPageObject from '../pages/ExperimentalTabsPageObject.macos';
import { BOOT_APP_TIMEOUT, PAGE_TIMEOUT } from '../../common/consts';
// Before testing begins, allow up to 60 seconds for app to open
describe('Experimental Tabs Testing Initialization', function () {
it('Wait for app load', () => {
NavigateAppPage.waitForPageDisplayed(BOOT_APP_TIMEOUT);
expect(NavigateAppPage.isPageLoaded()).toBeTruthy();
});
it('Click and navigate to Experimental Tabs test page', () => {
/* Scroll to component test page button in scrollview if not already visible*/
ExperimentalTabsPageObject.scrollToComponentButton();
ExperimentalTabsPageObject.waitForButtonDisplayed(PAGE_TIMEOUT);
/* Click on component button to navigate to test page */
NavigateAppPage.clickAndGoToExperimentalTabsPage();
ExperimentalTabsPageObject.waitForPageDisplayed(PAGE_TIMEOUT);
expect(ExperimentalTabsPageObject.isPageLoaded()).toBeTruthy();
});
});

Просмотреть файл

@ -1,4 +1,4 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import ExperimentalTabsPageObject from '../pages/ExperimentalTabsPageObject.win';
import { TAB_A11Y_ROLE, TABITEM_A11Y_ROLE, BOOT_APP_TIMEOUT, PAGE_TIMEOUT } from '../../common/consts';

Просмотреть файл

@ -0,0 +1,25 @@
import { TEXT_TESTPAGE, TEXT_TEST_COMPONENT, HOMEPAGE_TEXT_BUTTON } from '../../../FluentTester/TestComponents/Text/consts';
import { BasePage, By } from '../../common/BasePage.macos';
class TextPageObject extends BasePage {
/*****************************************/
/**************** Getters ****************/
/*****************************************/
get _testPage() {
return By(TEXT_TESTPAGE);
}
get _pageName() {
return TEXT_TESTPAGE;
}
get _primaryComponent() {
return By(TEXT_TEST_COMPONENT);
}
get _pageButton() {
return By(HOMEPAGE_TEXT_BUTTON);
}
}
export default new TextPageObject();

Просмотреть файл

@ -1,5 +1,5 @@
import { TEXT_TESTPAGE, TEXT_TEST_COMPONENT, HOMEPAGE_TEXT_BUTTON } from '../../../FluentTester/TestComponents/Text/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class TextPageObject extends BasePage {
/*****************************************/

Просмотреть файл

@ -0,0 +1,23 @@
import NavigateAppPage from '../../common/NavigateAppPage.macos';
import TextPageObject from '../pages/TextPageObject.macos';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';
// Before testing begins, allow up to 60 seconds for app to open
describe('Text Testing Initialization', function () {
it('Wait for app load', () => {
NavigateAppPage.waitForPageDisplayed(BOOT_APP_TIMEOUT);
expect(NavigateAppPage.isPageLoaded()).toBeTruthy();
});
it('Click and navigate to Text test page', () => {
/* Scroll to component test page button in scrollview if not already visible*/
TextPageObject.scrollToComponentButton();
TextPageObject.waitForButtonDisplayed(PAGE_TIMEOUT);
/* Click on component button to navigate to test page */
NavigateAppPage.clickAndGoToTextPage();
TextPageObject.waitForPageDisplayed(PAGE_TIMEOUT);
expect(TextPageObject.isPageLoaded()).toBeTruthy();
});
});

Просмотреть файл

@ -1,4 +1,4 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import TextPageObject from '../pages/TextPageObject.win';
import { TEXT_A11Y_ROLE, PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';

Просмотреть файл

@ -1,5 +1,5 @@
import { THEME_TESTPAGE, THEME_TEST_COMPONENT, HOMEPAGE_THEME_BUTTON } from '../../../FluentTester/TestComponents/Theme/consts';
import { BasePage, By } from '../../common/BasePage';
import { BasePage, By } from '../../common/BasePage.win';
class ThemePageObject extends BasePage {
/*****************************************/

Просмотреть файл

@ -1,4 +1,4 @@
import NavigateAppPage from '../../common/NavigateAppPage';
import NavigateAppPage from '../../common/NavigateAppPage.win';
import ThemePageObject from '../pages/ThemePageObject.win';
import { PAGE_TIMEOUT, BOOT_APP_TIMEOUT } from '../../common/consts';

Просмотреть файл

@ -0,0 +1,172 @@
const DUMMY_CHAR = '';
export const COMPONENT_SCROLL_COORDINATES = { x: -0, y: -100 }; // These are the offsets. Y is negative because we want the touch to move up (and thus it scrolls down)
/* Mac-Specific Selector. We use this to get elements on the test page */
export function By(identifier: string): WebdriverIO.Element {
return $('//*[@identifier="' + identifier + '"]');
}
/* The values in this enum map to the UI components we want to test in our app. We use this to
make the communication from our spec document to our page object easier. Please read below to
see why we have Primary/Secondary components. */
export const enum ComponentSelector {
Primary = 0, // this._primaryComponent
Secondary, // this._secondaryComponent
}
/****************************** IMPORTANT! PLEASE READ! **************************************************
* Every component's page object extends this. We can assume each test page will interact with at least
* two UI elements, so we'll add integration for two UI elements in this file (See *Getters* section below).
* Every additional UI element that a test page wants to interact with should be handled in that respective
* component's page object.
*********************************************************************************************************/
export class BasePage {
/******************************************************************/
/**************** UI Element Interaction Methods ******************/
/******************************************************************/
getAccessibilityRole(): string {
return this._primaryComponent.getAttribute('ControlType');
}
/* Gets the accessibility label of an UI element given the selector */
getAccessibilityLabel(componentSelector: ComponentSelector): string {
switch (componentSelector) {
case ComponentSelector.Primary:
return this._primaryComponent.getAttribute('Name');
case ComponentSelector.Secondary:
return this._secondaryComponent.getAttribute('Name');
}
}
/* 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) */
isPageLoaded(): boolean {
return this._testPage.isDisplayed();
}
/* Returns true if the test page's button is displayed (the button that navigates to each test page) */
isButtonInView(): boolean {
return this._pageButton.isDisplayed();
}
/* Scrolls until the desired test page's button is displayed. We use the scroll viewer UI element as the point to start scrolling.
* We use a negative number as the Y-coordinate because that enables us to scroll downwards */
scrollToComponentButton(): void {
if (!this.isButtonInView()) {
const scrollViewElement = $('~SCROLLVIEW_TEST_ID');
driver.touchScroll(COMPONENT_SCROLL_COORDINATES.x, COMPONENT_SCROLL_COORDINATES.y, scrollViewElement.elementId);
}
}
/* Waits for the test page to load. If the test page doesn't load before the timeout, it causes the test to fail. */
waitForPageDisplayed(timeout?: number): void {
browser.waitUntil(
() => {
return this.isPageLoaded();
},
{
timeout: timeout ?? this.waitForPageTimeout,
timeoutMsg: this._pageName + ' did not render correctly. Please see /errorShots for more information.',
interval: 1000,
},
);
}
/* Waits for the test page's button to be displayed. If the button doesn't load before the timeout, it causes the test to fail. */
waitForButtonDisplayed(timeout?: number): void {
browser.waitUntil(
() => {
return this.isButtonInView();
},
{
timeout: timeout ?? this.waitForPageTimeout,
timeoutMsg: 'Could not find the button to navigate to ' + this._pageName + '. Please see /errorShots for more information.',
interval: 1000,
},
);
}
/* Waits for the primary UI test element to be displayed. If the element doesn't load before the timeout, it causes the test to fail. */
waitForPrimaryElementDisplayed(timeout?: number): void {
browser.waitUntil(
() => {
return this._primaryComponent.isDisplayed();
},
{
timeout: timeout ?? this.waitForPageTimeout,
timeoutMsg:
'The primary UI element for testing did not display correctly. Please see /errorShots of the first failed test for more information.',
interval: 1000,
},
);
}
/* Scrolls to the primary UI test element until it is displayed. It uses the ScrollView that encapsulates each test page. */
scrollToTestElement(): void {
while (!this._primaryComponent.isDisplayed()) {
driver.touchScroll(COMPONENT_SCROLL_COORDINATES.x, COMPONENT_SCROLL_COORDINATES.y, $('~ScrollViewAreaForComponents').elementId);
}
}
/* A method that allows the caller to pass in a condition. A wrapper for waitUntil(). Once testing becomes more extensive,
* this will allow cleaner code within all the Page Objects. */
waitForCondition(condition?: () => boolean, errorMsg?: string, timeout?: number): void {
browser.waitUntil(
() => {
return condition();
},
{
timeout: timeout ?? this.waitForPageTimeout,
timeoutMsg: errorMsg ?? 'Error. Please see /errorShots and logs for more information.',
interval: 1000,
},
);
}
/*****************************************/
/**************** Getters ****************/
/*****************************************/
/* IMPORTANT:
* Each PageObject class that extends this class is expected to override these values.
* This is necessary because each page will have different IDs for their respective UI elements.
* DUMMY_CHAR is just a placeholder.
*/
// Returns: UI Element
// The Text component on each test page containing the title of that page. We can use this to determine if a test page has loaded correctly.
get _testPage(): WebdriverIO.Element {
return By(DUMMY_CHAR);
}
// Returns: UI Element
// The primary UI element used for testing on the given test page.
get _primaryComponent(): WebdriverIO.Element {
return By(DUMMY_CHAR);
}
// Returns: UI Element
// 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 _secondaryComponent(): WebdriverIO.Element {
return By(DUMMY_CHAR);
}
// Returns: UI Element
// The button that navigates you to the component's test page.
get _pageButton(): WebdriverIO.Element {
return By(DUMMY_CHAR);
}
// Returns: String
// Returns the name of the test page. Useful for error messages (see above).
get _pageName(): string {
return DUMMY_CHAR;
}
// Default timeout to wait until page is displayed (10s)
waitForPageTimeout: number = 15000;
}

Просмотреть файл

@ -1,8 +1,9 @@
const DUMMY_CHAR = '';
export const COMPONENT_SCROLL_COORDINATES = { x: -0, y: -100 }; // These are the offsets. Y is negative because we want the touch to move up (and thus it scrolls down)
export function By(testId: string): WebdriverIO.Element {
return $('~' + testId);
/* Win32/UWP-Specific Selector. We use this to get elements on the test page */
export function By(identifier: string): WebdriverIO.Element {
return $('~' + identifier);
}
/* The values in this enum map to the UI components we want to test in our app. We use this to
@ -66,9 +67,11 @@ export class BasePage {
() => {
return this.isPageLoaded();
},
timeout ?? this.waitForPageTimeout,
this._pageName + ' did not render correctly. Please see /errorShots of the first failed test for more information.',
1000,
{
timeout: timeout ?? this.waitForPageTimeout,
timeoutMsg: this._pageName + ' did not render correctly. Please see /errorShots for more information.',
interval: 1000,
},
);
}
@ -78,11 +81,11 @@ export class BasePage {
() => {
return this.isButtonInView();
},
timeout ?? this.waitForPageTimeout,
'The button to navigate to the ' +
this._pageName +
' was not displayed correctly. Please see /errorShots of the first failed test for more information.',
1000,
{
timeout: timeout ?? this.waitForPageTimeout,
timeoutMsg: 'Could not find the button to navigate to ' + this._pageName + '. Please see /errorShots for more information.',
interval: 1000,
},
);
}
@ -92,9 +95,12 @@ export class BasePage {
() => {
return this._primaryComponent.isDisplayed();
},
timeout ?? this.waitForPageTimeout,
'The primary UI element for testing did not display correctly. Please see /errorShots of the first failed test for more information.',
1000,
{
timeout: timeout ?? this.waitForPageTimeout,
timeoutMsg:
'The primary UI element for testing did not display correctly. Please see /errorShots of the first failed test for more information.',
interval: 1000,
},
);
}
@ -112,9 +118,11 @@ export class BasePage {
() => {
return condition();
},
timeout ?? this.waitForPageTimeout,
errorMsg ?? 'Error. Please see /errorShots and logs for more information.',
1000,
{
timeout: timeout ?? this.waitForPageTimeout,
timeoutMsg: errorMsg ?? 'Error. Please see /errorShots and logs for more information.',
interval: 1000,
},
);
}

Просмотреть файл

@ -0,0 +1,185 @@
import { HOMEPAGE_CHECKBOX_BUTTON } from '../../FluentTester/TestComponents/Checkbox/consts';
import { HOMEPAGE_BUTTON_BUTTON } from '../../FluentTester/TestComponents/Button/consts';
import { HOMEPAGE_CALLOUT_BUTTON } from '../../FluentTester/TestComponents/Callout/consts';
import { HOMEPAGE_CONTEXTUALMENU_BUTTON } from '../../FluentTester/TestComponents/ContextualMenu/consts';
import { HOMEPAGE_EXPERIMENTAL_TABS_BUTTON } from '../../FluentTester/TestComponents/TabsExperimental/consts';
import { HOMEPAGE_FOCUSTRAPZONE_BUTTON } from '../../FluentTester/TestComponents/FocusTrapZone/consts';
import { HOMEPAGE_FOCUSZONE_BUTTON } from '../../FluentTester/TestComponents/FocusZone/consts';
import { HOMEPAGE_ICON_BUTTON } from '../../FluentTester/TestComponents/Icon/consts';
import { HOMEPAGE_LINK_BUTTON } from '../../FluentTester/TestComponents/Link/consts';
import { HOMEPAGE_MENU_BUTTON } from '../../FluentTester/TestComponents/MenuButton/consts';
import { HOMEPAGE_PERSONA_BUTTON } from '../../FluentTester/TestComponents/Persona/consts';
import { HOMEPAGE_PERSONACOIN_BUTTON } from '../../FluentTester/TestComponents/PersonaCoin/consts';
import { HOMEPAGE_PRESSABLE_BUTTON } from '../../FluentTester/TestComponents/Pressable/consts';
import { HOMEPAGE_RADIOGROUP_BUTTON } from '../../FluentTester/TestComponents/RadioGroup/consts';
import { HOMEPAGE_SEPARATOR_BUTTON } from '../../FluentTester/TestComponents/Separator/consts';
import { HOMEPAGE_SVG_BUTTON } from '../../FluentTester/TestComponents/Svg/consts';
import { HOMEPAGE_TEXT_BUTTON } from '../../FluentTester/TestComponents/Text/consts';
import { HOMEPAGE_TABS_BUTTON } from '../../FluentTester/TestComponents/Tabs/consts';
import { HOMEPAGE_THEME_BUTTON } from '../../FluentTester/TestComponents/Theme/consts';
import { BASE_TESTPAGE } from '../../FluentTester/TestComponents/Common/consts';
import { By, BasePage } from './BasePage.macos';
class NavigateAppPage extends BasePage {
clickAndGoToButtonPage() {
this.buttonPage.click();
}
clickAndGoToCalloutPage() {
this.calloutPage.click();
}
clickAndGoToCheckboxPage() {
this.checkboxPage.click();
}
clickAndGoToContextualMenuPage() {
this.contextualMenuPage.click();
}
clickAndGoToFocusTrapZonePage() {
this.focusTrapZonePage.click();
}
clickAndGoToFocusZonePage() {
this.focusZonePage.click();
}
clickAndGoToIconPage() {
this.iconPage.click();
}
clickAndGoToLinkPage() {
this.linkPage.click();
}
clickAndGoToMenuButtonPage() {
this.menuButtonPage.click();
}
clickAndGoToPersonaPage() {
this.personaPage.click();
}
clickAndGoToPersonaCoinPage() {
this.personaCoinPage.click();
}
clickAndGoToPressablePage() {
this.pressablePage.click();
}
clickAndGoToRadioGroupPage() {
this.radioGroupPage.click();
}
clickAndGoToSeparatorPage() {
this.separatorPage.click();
}
clickAndGoToSvgPage() {
this.svgPage.click();
}
clickAndGoToTextPage() {
this.textPage.click();
}
clickAndGoToTabsPage() {
this.tabsPage.click();
}
clickAndGoToThemePage() {
this.themePage.click();
}
clickAndGoToExperimentalTabsPage() {
this.experimentalTabsPage.click();
}
/*
** Returns the StealthButton element on the left-hand column that navigates to each page
*/
get _testPage() {
return By(BASE_TESTPAGE);
}
private get buttonPage() {
return By(HOMEPAGE_BUTTON_BUTTON);
}
private get calloutPage() {
return By(HOMEPAGE_CALLOUT_BUTTON);
}
private get checkboxPage() {
return By(HOMEPAGE_CHECKBOX_BUTTON);
}
private get contextualMenuPage() {
return By(HOMEPAGE_CONTEXTUALMENU_BUTTON);
}
private get focusTrapZonePage() {
return By(HOMEPAGE_FOCUSTRAPZONE_BUTTON);
}
private get focusZonePage() {
return By(HOMEPAGE_FOCUSZONE_BUTTON);
}
private get iconPage() {
return By(HOMEPAGE_ICON_BUTTON);
}
private get linkPage() {
return By(HOMEPAGE_LINK_BUTTON);
}
private get menuButtonPage() {
return By(HOMEPAGE_MENU_BUTTON);
}
private get personaPage() {
return By(HOMEPAGE_PERSONA_BUTTON);
}
private get personaCoinPage() {
return By(HOMEPAGE_PERSONACOIN_BUTTON);
}
private get pressablePage() {
return By(HOMEPAGE_PRESSABLE_BUTTON);
}
private get radioGroupPage() {
return By(HOMEPAGE_RADIOGROUP_BUTTON);
}
private get separatorPage() {
return By(HOMEPAGE_SEPARATOR_BUTTON);
}
private get svgPage() {
return By(HOMEPAGE_SVG_BUTTON);
}
private get textPage() {
return By(HOMEPAGE_TEXT_BUTTON);
}
private get tabsPage() {
return By(HOMEPAGE_TABS_BUTTON);
}
private get themePage() {
return By(HOMEPAGE_THEME_BUTTON);
}
private get experimentalTabsPage() {
return By(HOMEPAGE_EXPERIMENTAL_TABS_BUTTON);
}
}
export default new NavigateAppPage();

Просмотреть файл

@ -19,7 +19,7 @@ import { HOMEPAGE_TEXT_BUTTON } from '../../FluentTester/TestComponents/Text/con
import { HOMEPAGE_TABS_BUTTON } from '../../FluentTester/TestComponents/Tabs/consts';
import { HOMEPAGE_THEME_BUTTON } from '../../FluentTester/TestComponents/Theme/consts';
import { BASE_TESTPAGE } from '../../FluentTester/TestComponents/Common/consts';
import { By, BasePage } from './BasePage';
import { By, BasePage } from './BasePage.win';
class NavigateAppPage extends BasePage {
clickAndGoToButtonPage() {

Просмотреть файл

@ -17,7 +17,8 @@
"test": "fluentui-scripts jest",
"macos": "react-native run-macos --scheme FluentTester --project-path src",
"prettier": "fluentui-scripts prettier",
"prettier-fix": "fluentui-scripts prettier --fix true"
"prettier-fix": "fluentui-scripts prettier --fix true",
"e2etest": "wdio"
},
"dependencies": {
"@fluentui-react-native/tester": "^0.49.0",
@ -33,11 +34,22 @@
"@rnx-kit/cli": "^0.5.27",
"@rnx-kit/metro-config": "^1.2.3",
"@uifabricshared/build-native": "^0.1.1",
"@wdio/appium-service": "^6.5.0",
"@wdio/cli": "^6.5.0",
"@wdio/jasmine-framework": "^6.5.0",
"@wdio/local-runner": "^6.5.0",
"@wdio/spec-reporter": "^6.5.0",
"@wdio/sync": "^6.5.0",
"appium-mac2-driver": "0.14.1",
"metro-config": "^0.66.2",
"metro-react-native-babel-preset": "^0.66.2",
"react-native-svg-transformer": "^0.14.3",
"react-native-test-app": "^0.9.13",
"react-test-renderer": "17.0.1"
"react-test-renderer": "17.0.1",
"ts-node": "^8.10.1",
"tsconfig-paths": "^3.9.0",
"typescript": "3.8.3",
"webdriverio": "^6.5.0"
},
"jest": {
"preset": "react-native"

12
apps/macos/tsconfig.json Normal file
Просмотреть файл

@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"*": ["*"],
"src/*": ["./src/*"]
},
"types": ["@wdio/sync", "@wdio/jasmine-framework", "node", "@types/jasmine"]
},
"include": ["src", "../fluent-tester/src"]
}

205
apps/macos/wdio.conf.js Normal file
Просмотреть файл

@ -0,0 +1,205 @@
const fs = require('fs');
const defaultWaitForTimeout = 20000;
const defaultConnectionRetryTimeout = 20000;
const jasmineDefaultTimeout = 45000; // 45 seconds for Jasmine test timeout
exports.config = {
runner: 'local', // Where should your test be launched
specs: ['../fluent-tester/src/E2E/Button/specs/*.macos.ts'],
exclude: [
/* 'path/to/excluded/files' */
],
maxInstances: 30,
capabilities: [
{
maxInstances: 1, // Maximum number of total parallel running workers.
platformName: 'mac',
automationName: 'Mac2',
bundleId: 'com.microsoft.ReactTestApp',
},
],
/*
** ===================
** Test Configurations
** ===================
** Define all options that are relevant for the WebdriverIO instance here
*/
logLevel: 'info', // Level of logging verbosity: trace | debug | info | warn | error | silent
// If you only want to run your tests until a specific amount of tests have failed use bail (default is 0 - don't bail, run all tests).
bail: 0,
waitforTimeout: defaultWaitForTimeout, // Default timeout for all waitForXXX commands.
connectionRetryTimeout: defaultConnectionRetryTimeout, // Timeout for any WebDriver request to a driver or grid.
connectionRetryCount: 3, // Maximum count of request retries to the Selenium server.
port: 4723, // default appium port
services: [
[
'appium',
{
logPath: './reports/',
},
],
],
framework: 'jasmine',
jasmineNodeOpts: {
defaultTimeoutInterval: jasmineDefaultTimeout,
},
// The number of times to retry the entire specfile when it fails as a whole.
// Adding an extra retry will hopefully reduce the risk of engineers seeing a false-negative
specFileRetries: 3,
reporters: ['spec'],
/*
** ===================
** Hooks
** ===================
** WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance
** it and to build services around it. You can either apply a single function or an array of
** methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got
** resolved to continue.
*/
/**
* Gets executed once before all workers get launched.
* @param {Object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
*/
//onPrepare: function (config, capabilities) {},
/**
* Gets executed before a worker process is spawned and can be used to initialise specific service
* for that worker as well as modify runtime environments in an async fashion.
* @param {String} cid capability id (e.g 0-0)
* @param {[type]} caps object containing capabilities for session that will be spawn in the worker
* @param {[type]} specs specs to be run in the worker process
* @param {[type]} args object that will be merged with the main configuration once worker is initialised
* @param {[type]} execArgv list of string arguments passed to the worker process
*/
// onWorkerStart: function (cid, caps, specs, args, execArgv) {
// },
/**
* Gets executed just before initialising the webdriver session and test framework. It allows you
* to manipulate configurations depending on the capability or spec.
* @param {Object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
* @param {Array.<String>} specs List of spec file paths that are to be run
*/
beforeSession: function (/*config, capabilities, specs*/) {
fs.mkdirSync('./errorShots', {recursive: true});
},
/**
* Gets executed before test execution begins. At this point you can access to all global
* variables like `browser`. It is the perfect place to define custom commands.
* @param {Array.<Object>} capabilities list of capabilities details
* @param {Array.<String>} specs List of spec file paths that are to be run
*/
before: function () {
require('ts-node').register({files: true});
},
/**
* Runs before a WebdriverIO command gets executed.
* @param {String} commandName hook command name
* @param {Array} args arguments that command would receive
*/
// beforeCommand: function (commandName, args) {
// },
/**
* Hook that gets executed before the suite starts
* @param {Object} suite suite details
*/
// beforeSuite: function (suite) {
// },
/**
* Function to be executed before a test (in Mocha/Jasmine) starts.
*/
// beforeTest: function (test, context) {
// },
/**
* Hook that gets executed _before_ a hook within the suite starts (e.g. runs before calling
* beforeEach in Mocha)
*/
// beforeHook: function (test, context) {
// },
/**
* Hook that gets executed _after_ a hook within the suite starts (e.g. runs after calling
* afterEach in Mocha)
*/
// afterHook: function (test, context, { error, result, duration, passed, retries }) {
// },
/**
* Function to be executed after a test (in Mocha/Jasmine).
*/
afterTest: function (test, context, results) {
// if test passed, ignore, else take and save screenshot. Unless it's the first test that boots the app,
// it may be useful to have a screenshot of the app on load.
if (results.passed) {
return;
}
// get current test title and clean it, to use it as file name
const fileName = encodeURIComponent(test.description.replace(/\s+/g, '-'));
// build file path
const filePath = './errorShots/' + fileName + '.png';
// save screenshot
browser.saveScreenshot(filePath);
},
/**
* Hook that gets executed after the suite has ended
* @param {Object} suite suite details
*/
// afterSuite: function (suite) {
// },
/**
* Runs after a WebdriverIO command gets executed
* @param {String} commandName hook command name
* @param {Array} args arguments that command would receive
* @param {Number} result 0 - command success, 1 - command error
* @param {Object} error error object if any
*/
// afterCommand: function (commandName, args, result, error) {
// },
/**
* Gets executed after all tests are done. You still have access to all global variables from
* the test.
* @param {Number} result 0 - test pass, 1 - test fail
* @param {Array.<Object>} capabilities list of capabilities details
* @param {Array.<String>} specs List of spec file paths that ran
*/
// after: function (result, capabilities, specs) {
// },
/**
* Gets executed right after terminating the webdriver session.
* @param {Object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
* @param {Array.<String>} specs List of spec file paths that ran
*/
// afterSession: function (config, capabilities, specs) {
// },
/**
* Gets executed after all workers got shut down and the process is about to exit. An error
* thrown in the onComplete hook will result in the test run failing.
* @param {Object} exitCode 0 - success, 1 - fail
* @param {Object} config wdio configuration object
* @param {Array.<Object>} capabilities list of capabilities details
* @param {<Object>} results object containing test results
*/
onComplete: function (exitCode, config, capabilities, results) {
//console.log('<<< TESTING FINISHED >>>');
},
/**
* Gets executed when a refresh happens.
* @param {String} oldSessionId session ID of the old session
* @param {String} newSessionId session ID of the new session
*/
//onReload: function(oldSessionId, newSessionId) {
//}
};

Просмотреть файл

@ -45,14 +45,8 @@
"@uifabricshared/build-native": "^0.1.1",
"@fluentui-react-native/eslint-config-rules": "^0.1.1",
"@wdio/allure-reporter": "5.22.4",
"@wdio/appium-service": "5.18.2",
"@wdio/cli": "5.23.0",
"@wdio/jasmine-framework": "5.18.6",
"@wdio/local-runner": "5.23.0",
"@wdio/spec-reporter": "5.22.4",
"@wdio/sync": "5.20.1",
"allure-commandline": "2.13.0",
"appium": "1.17.1",
"appium": "1.20.0",
"metro-config": "^0.66.2",
"metro-react-native-babel-preset": "^0.66.2",
"react-native-svg-transformer": "^0.14.3",
@ -60,7 +54,13 @@
"ts-node": "^8.10.1",
"tsconfig-paths": "^3.9.0",
"typescript": "3.8.3",
"webdriverio": "5.22.4"
"webdriverio": "^6.5.0",
"@wdio/appium-service": "^6.5.0",
"@wdio/cli": "^6.5.0",
"@wdio/jasmine-framework": "^6.5.0",
"@wdio/local-runner": "^6.5.0",
"@wdio/spec-reporter": "^6.5.0",
"@wdio/sync": "^6.5.0"
},
"jest": {
"preset": "react-native"

Просмотреть файл

@ -45,13 +45,14 @@ exports.config = {
connectionRetryCount: 3, // Maximum count of request retries to the Selenium server.
port: 4723, // default appium port
services: ['appium'],
appium: {
logPath: './reports/',
args: {
port: '4723',
},
},
services: [
[
'appium',
{
logPath: './reports/',
},
],
],
framework: 'jasmine',
jasmineNodeOpts: {
@ -113,6 +114,7 @@ exports.config = {
before: function () {
// not needed for Cucumber
require('ts-node').register({ files: true });
browser.maximizeWindow();
},
/**

Просмотреть файл

@ -32,14 +32,8 @@
"@types/jasmine": "3.5.10",
"@uifabricshared/build-native": "0.1.1",
"@wdio/allure-reporter": "5.22.4",
"@wdio/appium-service": "5.18.2",
"@wdio/cli": "5.23.0",
"@wdio/jasmine-framework": "5.18.6",
"@wdio/local-runner": "5.23.0",
"@wdio/spec-reporter": "5.22.4",
"@wdio/sync": "5.20.1",
"allure-commandline": "2.13.0",
"appium": "1.17.1",
"appium": "1.20.0",
"metro-config": "^0.66.2",
"metro-react-native-babel-preset": "^0.66.2",
"react-native-test-app": "^0.9.13",
@ -48,7 +42,13 @@
"ts-node": "^8.10.1",
"tsconfig-paths": "^3.9.0",
"typescript": "3.8.3",
"webdriverio": "5.22.4"
"webdriverio": "^6.5.0",
"@wdio/appium-service": "^6.5.0",
"@wdio/cli": "^6.5.0",
"@wdio/jasmine-framework": "^6.5.0",
"@wdio/local-runner": "^6.5.0",
"@wdio/spec-reporter": "^6.5.0",
"@wdio/sync": "^6.5.0"
},
"workspaces": {
"nohoist": [

Просмотреть файл

@ -50,13 +50,14 @@ exports.config = {
connectionRetryCount: 3, // Maximum count of request retries to the Selenium server.
port: 4723, // default appium port
services: ['appium'],
appium: {
logPath: './reports/',
args: {
port: '4723',
},
},
services: [
[
'appium',
{
logPath: './reports/',
},
],
],
framework: 'jasmine',
jasmineNodeOpts: {
@ -118,6 +119,7 @@ exports.config = {
before: function () {
// not needed for Cucumber
require('ts-node').register({files: true});
browser.maximizeWindow();
},
/**

Просмотреть файл

@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Adding MacOS E2E testing to CI pipeline",
"packageName": "@fluentui-react-native/tester",
"email": "safreibe@microsoft.com",
"dependentChangeType": "patch"
}

Просмотреть файл

@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Adding MacOS E2E testing to CI pipeline",
"packageName": "@fluentui-react-native/tester-win32",
"email": "safreibe@microsoft.com",
"dependentChangeType": "patch"
}

1479
yarn.lock

Разница между файлами не показана из-за своего большого размера Загрузить разницу